前言

Wassup guys,我是Edison

今天是「C语言」之「趣味数学」,第213天!

Let’s get it!

文章目录

  • 前言
  • 1. 题目描述
  • 2. 问题分析
    • 声明结构体
    • 定义结构体类型的变量
    • 结构体变量的引用
    • 结构体数组
    • 结构体数组的初始化
    • 使用 typedef 来定义类型
  • 3. 算法设计
  • 4. 确定程序框架
  • 5. 流程图展示
  • 6. 完整程序
  • 7. 问题拓展

1. 题目描述

编写一个计算个人所得税的程序,要求输入收入金额后,能够输出应缴的个人所得税。
 

个人所得税征收办法如下:

起征点为 3500 元。
 
(1) 不超过 1500元 的部分,征收 3%
 
(2) 超过 1500~4500 元的部分,征收 10%
 
(3) 超过 4500~9000 元的部分,征收 20%
 
(4) 超过 9000~35000 元的部分,征收 25%
 
(5) 超过 35000~55000 元的部分,征收 30%
 
(6) 超过 55000~80000 元的部分,征收 35%
 
(7) 超过 80000 元以上的,征收 45%

2. 问题分析

分析题目特点,可以考虑使用 结构体 来描述题目中的条件。
 
下面先讲解C语言中结构体的语法要点。

声明结构体

C语言中允许用户自己定义结构体,它相当于其他高级语言中的 “记录”。

声明一个结构体类型的一般形式为:

struct 结构体名{结构体成员列表}

对结构体中的各个成员都应该进行类型声明,即:

类型名 成员名

例如


上面我们定义了一个新的结构体类型 struct user
 
它包含了 idnameageaddress 这 4 个不同类型的数据项。
 
可以说,struct user 是一个新的类型名,它和系统提供的标准类型一样都可以用来定义变量的类型。

定义结构体类型的变量

声明结构体之后还需要定义结构体类型的变量。
 
因为声明后的结构体中并没有具体数据,系统也不会对它分配内存单元。
 
如果想在程序中使用结构体类型的数据,就必须定义结构体类型的变量,然后将数据存放在其中。
 
3 种定义结构体类型变量的方法。

① 先声明结构体类型再定义变量名

可以使用上面声明的 struct user 类型来定义变量,例如:

struct user user1, user2;

其中 struct user 是结构体类型名,而 user1user2 是定义的 struct user 类型的变量。
 
user1user2 都具有 struct user 类型的结构,即它们都包含了 idnameageaddress 这几个数据项。

② 声明类型的同时定义变量名


上面代码声明了 struct user 类型的结构体,同时定义了两个 struct user 类型的结构体变量。

③ 直接定义结构体类型变量

使用此方式可以省略掉结构体名,例如:

结构体变量的引用

不能将结构体变量作为一个整体来操作,而要对其中的各个成员分别进行操作。
 
引用结构体变量中成员的方式为:

结构体变量.成员名

例如:

user1.id —— 表示引用 user1 变量中的 id 成员

结构体数组

结构体数组与普通的数值型数组的区别在于,结构体数组中的每个数组元素都是一个结构体类型的数据,它们都包括各自的成员。
 
定义结构体数组与定义结构体变量的方法类似,只需说明其为数组即可。例如:

上面代码中定义了一个数组 user1,其中的元素为 struct user 类型数据,该数据包含了 5 个元素。也可以直接定义一个结构体数组,例如:

数组中的各个元素在内存中是连续存放的

结构体数组的初始化

结构体数组初始化的一般形式是在定义数组的后面跟上初值列表,例如:

使用 typedef 来定义类型

在 C 语言中除了可以使用标准类型,如 intchar 等,以及自己声明的结构体、共用体、指针类型等,还可以使用 typedef 来声明新的类型名以代替已有的类型名。

typedef int INT

还可以使用 typedef 来声明结构体类型:

上面代码声明了一个新类型名 USER,它代表了上面指定的一个结构体类型,此时可以使用 USER 来定义变量。

USER u1;USER *p;

上面代码定义了一个 USER 类型的变量 u1 及一个指向 USER 类型变量的指针变量 p

3. 算法设计

由问题分析中讲解的 C 语言中结构体的相关知识可知,这里可以使用结构体数组存放不同的税率范围。
 
接着使用 for 循环遍历每一个征税范围,将个人收入中超出起征点的金额在每个征税范围内应缴纳的税款累加起来,就得到最后应缴纳的个人所得税。

4. 确定程序框架

(1) 定义结构体 TAXTABLE,该结构体描述了征税的范围及对应不同范围的税率。

typedef struct{long start;long end;double taxrate;}TAXTABLE;

在结构体 TAXTABLE 中,start 成员表示征税范围的起点,end 成员表示征税范围的终点,taxrate 成员表示该范围内的征税税率。

(2) 定义结构体数组 TaxTable, 将征税范围及税率存入该变量中。

TAXTABLE TaxTable[] = { {0, 1500, 0.03}, {1500, 4500, 0.10}, {4500, 9000, 0.20}, {9000, 35000, 0.25},{35000, 55000, 0.30}, {55000, 80000, 0.35}, {80000, 1e10, 0.45} };

(3) 定义计算税率的函数 CaculateTax

其中, profit 为个人收入, TAXBASE 是个税起征点。
 
profit-TAXBASE 是个人收入中超出个税起征点的部分, 仍存入 profit 变量中, 在 CaculateTax 中要计算出这部分收入的纳税金额。

CaculateTax() 函数中使用了 for 循环,循环变量为 i,循环次数与 TaxTable 数组中的元素个数相同。
 
在循环体中用 profit,注意此时的 profit 中存放的是个人收入中超过个税起征点的部分,与征税范围做比较。
 
如果 TaxTable[i].end > profit > TaxTable[i].start,即 profit 恰好处于某个范围内,则在该范围内应缴税金额为 (profit-TaxTable[i].start) * TaxTable[i].taxrate
 
如果 profit > TaxTable[i].end,则在该范围内应缴税金额为 (TaxTable[i].end - TaxTable[i]. start) * TaxTable[i].taxrate
 
使用 for 循环将每个征收范围遍历一遍,将各个范围内产生的缴税金额累加起来,就得到应该缴纳的个人所得税的总金额。

5. 流程图展示

6. 完整程序

完整代码

#include #define TAXBASE 3500//定义结构体typedef struct{long start;long end;double taxrate;}TAXTABLE;//定义结构数组TAXTABLE TaxTable[] = { {0, 1500, 0.03}, {1500, 4500, 0.10}, {4500, 9000, 0.20}, {9000, 35000, 0.25},{35000, 55000, 0.30}, {55000, 80000, 0.35}, {80000, 1e10, 0.45} };//CaculateTax() 函数double CaculateTax(long profit){int i;double tax = 0.0;profit -= TAXBASE;/*超过个税起征点的收入*/for (i = 0; i < sizeof(TaxTable) / sizeof(TAXTABLE); i++){/*判断profit是否在当前的缴税范围内*/if (profit > TaxTable[i].start){if (profit > TaxTable[i].end)/* profit 超过个税起征点的收入 */{tax += (TaxTable[i].end - TaxTable[i].start) * TaxTable[i].taxrate;}else/* profit 未超过当前的缴税范围 */{tax += (profit - TaxTable[i].start) * TaxTable[i].taxrate;}profit -= TaxTable[i].end;printf("征税范围:%3ld - %ld 该范围内缴税金额:%6.2f 超出该范围的金额:%3ld\n", TaxTable[i].start, TaxTable[i].end, tax, (profit) > 0 " />: 0);}}return tax;}int main(){long profit;double tax;printf("请输入个人收入金额:");scanf("%ld", &profit);tax = CaculateTax(profit);printf("您的个人所得税为:%12.2f\n", tax);return 0;}

运行结果

代码贴图

7. 问题拓展

在解决该问题时我们用到了结构体,并且已经知道引用结构体变量中成员的方式为:结构体变量名.成员名
 
事实上,除了这种引用方式以外,在C语言中还可以使用 指针 来指向结构体变量和结构体数组。
 
在本题中,可使用下面代码来定义指针 p 为指向 TAXTABLE 类型结构体的指针变量:TAXTABLE *p
 
这样定义后,就可以使用指针 p 来引用 TAXTABLE 类型的结构体变量中的成员。
 
引用方式有两种:(*p).成员名 或者 p->成员名

下面,我们就使用 结构体指针 来改写原来程序中的 CaculateTax() 函数,改写后的代码如下:

代码解释

在改写后的 CaculateTax() 函数中, 指针 p 是指向 TAXTABLE 类型数据的指针变量。
 
for 循环语句中先给 p 赋初值 TaxTableTaxTable 也就是数组 TaxTable起始地址。这样, 就可以使用 指针变量 来引用 TaxTable 中的各个数组元素(每个数组元素是一个结构体变量)的成员值。
 
在第一次循环时, p 指向 TaxTable[0], 则 p->startp->endp->taxrate 引用的都是 TaxTable[0] 中的成员。
 
然后执行 p++, 使 p 自增 1, 此时 p 所增加的值为结构体数组 TaxTable 中一个元素所占有的字节数, 即 sizeof(TAXTABLE)
 
在执行 p++ 后, p 的值变为 TaxTable+1,即 p 指向数组元素 TaxTable[1] 的起始地址了, 这样在第二次循环时的 p->startp->endp->taxrate 引用的就都是 TaxTable[1] 中的成员了。
 
接着再执行 p++, 此时 p 的值变为 TaxTable+2, 即 p 指向数组元素 TaxTable[2] 的起始地址, 这样在第三次循环时的 p->startp->endp->taxrate 引用的就都是 TaxTable[2] 中的成员了。
 
这样不断循环下去, p 的值不断自增, 直到对 TaxTable 数组中最后一个数组元素操作完毕为止。