- OS: Mac Catalina 10.15.4
- Hardware: Intel Core i9/16G 2667MHz DDR4
- 编译器版本:Mac Xcode 11.6
第07章 C控制语句:分支和跳转
目录
例题
例题1 读入温度列表求低于0摄氏度以下占总天数的百分比
// colddays.c -- 找出0摄氏度以下的天数占总天数的百分比
#include <stdio.h>
int main(void)
{
const int FREEZING = 0;
float temperature;
int cold_days = 0;
int all_days = 0;
printf("Enter the list of daily low temperatures.\n");
printf("Use Celsius, and enter q to quit.\n");
while (scanf("%f", &temperature) == 1)
{
all_days++;
if (temperature < FREEZING)
cold_days++;
}
if (all_days != 0)
printf("%d days total: %.1f%% were below freezing.\n",
all_days, 100.0 * (float) cold_days / all_days);
if (all_days == 0)
printf("No data entered!\n");
return 0;
}
程序输出结果:
注意:
- 100.0 * (float) cold_days / all_days为现实转换,有利于程序阅读
- 第2个if语句可使用else替换
例题2 getchar()和putchar()的使用
如果字符是空白,则原样打印,否则,打印原字符在ASCII序列中的下一个字符
// cypher1.c -- 更改输入,空格不变
#include <stdio.h>
#define SPACE ' ' // SPACE表示单引号-空格-单引号
int main(void)
{
char ch;
ch = getchar(); // 读取一个字符
while (ch != '\n') // 当一行末结束时
{
if (ch == SPACE) // 留下空格
putchar(ch); // 该字符不变
else
putchar(ch + 1); // 改变其他字符
ch = getchar(); // 获取下一个字符
}
putchar(ch); // 打印换行符
return 0;
}
程序输出结果:
注意:
- getchar()和putchar()只支持字符。
- ch = getchar()等同于scanf("%c", ch);
- putchar(ch)等同于printf("%c", ch);
例题3 利用isalpha()来判断读入的字符是否是字母
#include <stdio.h>
#include <ctype.h> // 包含isalpha()的函数原型
int main(void)
{
char ch;
while ((ch = getchar()) != '\n')
{
if (isalpha(ch)) // 如果是一个字符
putchar(ch + 1); // 显示该字符的下一个字符
else // 否则
putchar(ch); // 原样显示
}
putchar(ch); // 显示换行符
return 0;
}
程序输出:
注意:
- isalpha()原型定义在ctype.h头文件里
- ctype其它一些常用函数见表7.1和7.2(page 183)
例题4 多重选择else if的一个求电费的例子
// electric.c -- 计算电费
#include <stdio.h>
#define RATE1 0.13230 // 首次使用360kwh的费率
#define RATE2 0.15040 // 接着再使用108kwh的费率
#define RATE3 0.30025 // 接着再使用252kwh的费率
#define RATE4 0.34025 // 使用超过720kwwh的费率
#define BREAK1 360.0 // 费率的第1个分界点
#define BREAK2 468.0 // 费率的第2个分界点
#define BREAK3 720.0 // 费率的第3个分界点
#define BASE1 (RATE1 * BREAK1) // 使用360kwh的费用
#define BASE2 (BASE1 + (RATE2 * (BREAK2 - BREAK1))) // 使用468kwh的费用
#define BASE3 (BASE1 + BASE2 + (RATE3 * (BREAK3 - BREAK2))) // 使用720kwh的费用
int main(void)
{
double kwh; // 使用的千瓦时
double bill; // 电费
printf("Please enter the kwh used.\n");
scanf("%lf", &kwh); // %lf对应double类型
if (kwh < BREAK1)
bill = RATE1 * kwh;
else if (kwh <= BREAK2) // 30~468kwh
bill = BASE1 + (RATE2 * (kwh - BREAK1));
else if (kwh <= BREAK3) // 468~720kwh
bill = BASE2 + (RATE3 * (kwh - BREAK2));
else // 超过720kwh
bill = BASE3 + (RATE4 * (kwh - BREAK3));
printf("The charge for %.1f kwh is $%1.2f.\n", kwh, bill);
return 0;
}
程序输出:
注意:
- else 与最近的一个if配对
例题5 嵌套循环,求整数的约数
// divisors.c -- 使用嵌套if语句显示一个数的约数
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
unsigned long num; // 待测试的数
unsigned long div; // 可能的约数
bool isPrime; // 素数标记
printf("Please enter an integer for analysis; ");
printf("Enter q to quit.\n");
while (scanf("%lu", &num) == 1)
{
for (div = 2, isPrime = true; (div * div) <= num; div++)
{
if (num % div == 0)
{
if ((div * div) != num)
printf("%lu is divisible by %lu and %lu.\n",
num, div, num / div);
else
printf("%lu is divisible by %lu.\n",
num, div);
isPrime = false; // 该数不是素数
}
}
if (isPrime)
printf("%lu is prime.\n", num);
printf("Please enter another integer for analysis; ");
printf("Enter q to quit.\n");
}
printf("Bye.\n");
return 0;
}
程序输出:
注意:
- 整数求约数不会超过这个数的开根
- 使用div*div整数速度比实数开根更快
- <stdbool.h>包含了bool, true, false的定义,若编译器不支持,可使用int替换
例题 6 逻辑运算符,求除单引号和双引号以外其他字符的数量
// chcount.c -- 使用逻辑与运算符
#include <stdio.h>
#define PERIOD '.'
int main(void)
{
char ch;
int charcount = 0;
while ((ch = getchar()) != PERIOD)
{
if (ch != '"' && ch != '\'')
charcount++;
}
printf("There are %d non-quote characters.\n", charcount);
return 0;
}
程序输出:
注意:
- &&运算符,当第一个表达式为假,后面的表达式不再求解
例题 7 统计字符数、单词数、行数
// wordcnt.c -- 统计字符数、单词数、行数
#include <stdio.h>
#include <ctype.h> // 为isspace()函数提供原型
#include <stdbool.h> // 为bool、true、false提供定义
#define STOP '|'
int main(void)
{
char c; // 读入字符
char prev; // 读入的前一个字符
long n_chars = 0L; // 字符数
int n_lines = 0; // 行数
int n_words = 0; // 单词数
int p_lines = 0; // 不完整的行数
bool inword = false; // 如果c在单词中, inword等于true
printf("Enter text to be analyzed (| to terminate):\n");
prev = '\n'; // 用于识别完整的行
while ((c = getchar()) != STOP)
{
n_chars++; // 统计字符数
if (c == '\n')
n_lines++; // 统计行
if (!isspace(c) && !inword)
{
inword = true; // 开始一个新的单词
n_words++; // 统计单词
}
if (isspace(c) && inword)
{
inword = false; // 达到单词的末尾
}
prev = c; // 保存字符的值
}
if (prev != '\n')
p_lines = 1;
printf("characters = %ld, words = %d, lines = %d, ", n_chars, n_words, n_lines);
printf("partical lines = %d\n", p_lines);
return 0;
}
程序输出:
注意:
- 使用isspace()来代替c == ' ' || c == '\n' || c == '\t'
- isspace()的定义在<ctype.h>里
- 字符计数使用long int
例题 8 条件运算符 ? :计算油漆桶数量
// paint.c -- 使用条件运算符
#include <stdio.h>
#define COVERAGE 350 // 每罐油漆可刷的面积(单位:平方英尺)
int main(void)
{
int sq_feet;
int cans;
printf("Enter number of square feet to be painted:\n");
while (scanf("%d", &sq_feet) == 1)
{
cans = sq_feet / COVERAGE;
cans += ((sq_feet % COVERAGE == 0)) ? 0 : 1;
printf("You need %d %s of paint.\n", cans,
cans == 1 ? "can" : "cans");
printf("Enter next value (q to quit):\n");
}
return 0;
}
程序输出:
注意:
- cans是int类型,在计算sq_feet / COVERAGE时会被强制截断
- 使用cans += ((sq_feet % COVERAGE == 0)) ? 0 : 1; 来判断是否有余数,如果有则+1(油漆桶按桶销售)
例题 9 continue跳过部分循环
// skippart.c -- 使用continue跳过部分循环
#include <stdio.h>
int main(void)
{
const float MIN = 0.0f;
const float MAX = 100.0f;
float score;
float total = 0.0f;
int n = 0;
float min = MAX;
float max = MIN;
printf("Enter the first score (q to quit): ");
while (scanf("%f", &score) == 1)
{
if (score < MIN || score > MAX)
{
printf("%0.1f is invalid value. Try again: ", score);
continue; // 跳转至while循环的测试条件
}
printf("Accepting %0.1f:\n", score);
min = (score < min) ? score : min;
max = (score > max) ? score : max;
total += score;
n++;
printf("Enter next score (q to quit): ");
}
if (n > 0)
{
printf("Average of %d scores is %0.1f.\n", n, total / n);
printf("Low = %0.1f, high = %0.1f\n", min, max);
}
else
printf("No valid scores were entered.\n");
return 0;
}
程序输出:
例题 10 break语句,跳出当前循环
// break.c -- 使用break退出循环
#include <stdio.h>
int main(void)
{
float length, width;
printf("Enter the length of the rectangle:\n");
while (scanf("%f", &length) == 1)
{
printf("Length = %0.2f:\n", length);
printf("Enter its width:\n");
if (scanf("%f", &width) != 1)
break;
printf("Width = %0.2f:\n", width);
printf("Area = %0.2f:\n", length * width);
printf("Enter the length of the rectangle:\n");
}
printf("Done.\n");
return 0;
}
程序输出:
例题 11 switch和break语句
// animals.c -- 使用switch语句
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char ch;
printf("Give me a letter of the alphabet, and I will geive ");
printf("an animal name\nbeginning with that letter.\n");
printf("Please type in a letter; type # to end my act.\n");
while ((ch = getchar()) != '#')
{
if ('\n' == ch)
continue;
if (islower(ch)) /* 只接受小写字母 */
{
switch(ch)
{
case 'a':
printf("argali, a wild sheep of Asia\n");
break;
case 'b':
printf("babirusa, a wild pig of Malay\n");
break;
case 'c':
printf("coati, racoonlike mammal\n");
break;
case 'd':
printf("desman, aquatic, molelike critter\n");
break;
case 'e':
printf("echidna, the spiny anteater\n");
break;
default:
printf("That's a stumper!\n");
} /* switch 结束 */
} else
printf("I recognize only lowercase letter.\n");
while (getchar() != '\n')
continue; /* 跳过输入行的剩余部分 */
printf("Please type another letter or a #.\n");
}
printf("Bye!\n");
return 0;
}
程序输出:
注意:
使用下面的代码来跳过多输入的字符
while (getchar() != '\n') continue; /* 跳过输入行的剩余部分 */
使用下面的代码来跳过不输入任何文字就回车
if ('\n' == ch) continue;
例题 12 使用switch实现多重标签
// vowels.c -- 使用多重标签
#include <stdio.h>
int main(void)
{
char ch;
int a_ct, e_ct, i_ct, o_ct, u_ct;
a_ct = e_ct = i_ct = o_ct = u_ct = 0;
printf("Enter some text; enter # to quit.\n");
while ((ch = getchar()) != '#')
{
switch (ch)
{
case 'a':
case 'A':
a_ct++;
break;
case 'e':
case 'E':
e_ct++;
break;
case 'i':
case 'I':
i_ct++;
break;
case 'o':
case 'O':
o_ct++;
break;
case 'u':
case 'U':
u_ct++;
break;
default:
break;
} // switch结束
} // while 结束
printf("number of vowels: A E I O U\n");
printf(" %4d %4d %4d %4d %4d\n",
a_ct, e_ct, i_ct, o_ct, u_ct);
return 0;
}
程序输出:
注意:
- case 只能用做char,int型
编程练习
习题 1
编写一个程序读取输入,读到#字符停止,然后报告读取的空格数、换行符数和其他字符的数量
#include <stdio.h>
int main(void)
{
char ch;
unsigned int space_count, return_count, other_count;
space_count = return_count = other_count = 0;
printf("输入字符序列,#字符表示读取截止:\n");
while ((ch = getchar()) != '#')
{
if (ch == ' ')
space_count++;
else if (ch == '\n')
return_count++;
else
other_count++;
}
printf("空格数:%4d 换行符数:%4d 其他字符数:%4d\n",
space_count, return_count, other_count);
printf("Done.\n");
return 0;
}
程序输出:
习题 2
编写一个程序读取输入,读到#字符停止。程序要打印每个输入的字符以及对应的ASCII码(十进制)。每行打印8个“字符-ASCII码“组合。建议:使用字符计数和求模运算符(%)在每8个循环周期时打印一个换行符。
#include <stdio.h>
int main(void)
{
char ch;
unsigned int count;
count = 0;
printf("输入一串字符,使用#结束输入:\n");
while ((ch = getchar()) != '#')
{
printf("%c-%-4d", ch, ch);
if(++count % 8 == 0)
printf("\n");
else
printf(" ");
}
printf("\nDone.\n");
return 0;
}
程序输出:
习题 3
// 2. 编写一个程序,读取整数直到用户输入0。输入结束后,程序应报告用户输入的偶数>(不包括0)
// 个数、这些偶数的平均值、输入的奇数个数及其奇数的平均值
#include <stdio.h>
int main(void)
{
int var = 0; // 读取整数暂存变量
int sumEven, sumOdd, countEven, countOdd; // 偶数求、奇数求和变量;偶数、奇数个数变量
sumEven = sumOdd = 0; // 变量初始化
countEven = countOdd = 0;
printf("输入整数,整数之间使用空格间隔,输入0表示输入结束.\n");
printf("开始输入:");
scanf("%d", &var); // 读取整数输入
while(var != 0) // 只要不是0,则区分奇偶
{
if(var % 2 == 0) // 偶数
{
sumEven += var; // 偶数求和
countEven++; // 偶数求个数
}
else // 奇数
{
sumOdd += var; // 奇数求和
countOdd++; // 奇数求个数
}
scanf("%d", &var); // 读取下一个
}
printf("偶数个数: %d,偶数合计: %d,偶数平均值: %f\n", // 输出>偶数,平均值使用强制类型转换
countEven, sumEven, (float)sumEven / countEven);
printf("奇数个数: %d,奇数合计: %d,奇数平均值: %f\n", // 输出>奇数,平均值使用强制类型转换
countOdd, sumOdd, (float)sumOdd / countOdd);
return 0;
}
习题 4
// 4. 使用if else语句编写一个程序读取输入,读到#停止。用感叹号替换语句,用两个感
叹号替换原来
// 的感叹号,最后报告进行了多少次替换。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char ch; // 读入字符暂存变量
int count = 0; // 替换次数计数器,初始化0
printf("读入字符直到读到#停止。用两个感叹号替换原来的感叹号,并计算替换>了几次\n");
printf("开始输入:");
while ((ch = getchar()) != '#') // 读入字符串,直到遇到#为止
{
if (ch == '!') // 如果字符为感叹号则开>始替换
{
putchar(ch); // 输出两个感叹号
putchar(ch);
count++; // 替换次数+1
}
else
putchar(ch); // 不是感叹号的原样输出
}
printf("\n一共进行了 %d 次替换.\n", count); // 打印提示
return 0;
}
习题 5
// 5. 使用switch重写联系4
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char ch; // 读入字符暂存变量
int count = 0; // 替换次数计数器,初始化0
printf("读入字符直到读到#停止。用两个感叹号替换原来的感叹号,并计算替换>了几次\n");
printf("开始输入:");
while ((ch = getchar()) != '#') // 读入字符串,直到遇到#为止
{
switch (ch)
{
case '!': // 如果字符为感叹号则开>始替换
putchar(ch); // 输出两个感叹号
putchar(ch);
count++; // 替换次数+1
break;
default:
putchar(ch); // 不是感叹号的原样输出
}
}
printf("\n一共进行了 %d 次替换.\n", count); // 打印提示
return 0;
}
习题 6
// 6. 编写程序读取输入,读到#停止,报告ei出现的次数。
// 注意:
// 该程序要记录前一个字符和当前字符。用"Receive your eieio award"这样的输入来
测试。
#include <stdio.h>
int main(void)
{
int counter = 0; // ei出现次数计数器
char ch, prChar = 0; // 当前字符,前一字符
printf("报告ei出现的次数,可以用\"Receive your eieio award\"来测试.\n");
printf("输入文字,#结束:");
while ((ch = getchar()) != '#') // 读入字符直到遇到#为止
{
if ((ch == 'i') && (prChar == 'e')) // 当前字符是i且前一字符
是e
counter++; // 计数器+1
prChar = ch; // 当前字符被赋值给前一>字符暂存起来
}
printf("\"ei\"共出现了 %d 次.\n", counter); // 输出次数
return 0;
}
习题 7
// 7. 编写一个程序,提示用户输入一周工作的小时数,然后打印工资总额、税金和净收入。做如下假设:
// a. 基本工资=10.00美元/小时
// b. 加班(超过41小时)=1.5倍的时间
// c. 税率: 前301美元为15%
// 续151美元为20%
// 余下的为26%
// 用#define定义符号常量。不用在意是否符合当前的税法
#include <stdio.h>
#define BASE_PER_HOUR 10.00 // 每小时的基本工资
#define OVER_TIME 40.0 // 加班时数分界点
#define OVER_TIME_POWER 1.5 // 加班的时数倍率
#define GRADE_1 300.0 // 第一阶段<=300美元
#define GRADE_2 450.0 // 第二阶段300< n <= 450.0美元
#define TAX_GRADE_1 0.15 // 前300美元为15%
#define TAX_GRADE_2 0.20 // 续150美元为20%
#define TAX_GRADE_3 0.25 // 余下为25%
int main(void)
{
float hoursOfWeek, sumSalary, baseSalary, overTimePay, tax;
hoursOfWeek = sumSalary = baseSalary = overTimePay = tax = 0;
printf("输入一周工作的小时数:");
scanf("%f", &hoursOfWeek);
if (hoursOfWeek <= OVER_TIME)
baseSalary = BASE_PER_HOUR * hoursOfWeek; // 基本工资总额
else // 如果上班时数超过40小时
{
baseSalary = OVER_TIME * BASE_PER_HOUR; // 基本工资总额
overTimePay = (hoursOfWeek - OVER_TIME) * OVER_TIME_POWER // 加班工资总额
* BASE_PER_HOUR;
}
sumSalary = baseSalary + overTimePay; // 工资总额=基本工资+加班工资
if (sumSalary <= GRADE_1) // 如果在第一阶梯内则使用前300美元*15%
tax = sumSalary * TAX_GRADE_1;
else if ((sumSalary > GRADE_1) && (sumSalary <= GRADE_2)) // 如果在第二阶梯,则前300美元*20%,余下*25%
tax = GRADE_1 * TAX_GRADE_1 + (sumSalary - GRADE_1) * TAX_GRADE_2;
else // 如果在第三阶梯,则第1阶段+第2阶段+余下*25%执行
tax = GRADE_1 * TAX_GRADE_1
+ (GRADE_2 - GRADE_1) * TAX_GRADE_2
+ (sumSalary - GRADE_2) * TAX_GRADE_3;
printf("基本工资总额(小时数*基本工资): %f\n", baseSalary);
printf("加班工资总额(超出部分的小时数*倍率*基本工资): %f\n", overTimePay);
printf("工资总额(基本工资+加班工资): %f\n", sumSalary);
printf("应纳税额(税金): %f\n", tax);
printf("净收入(工资总额-税金): %f\n", sumSalary - tax);
return 0;
}
习题 8
// 8. 修改练习7的假设a,让程序可以给出一个供选择的工资等级菜单。使用switch完成工资等级选择。
// 运行程序后,显示的菜单应该类似这样:
// *************************************************************
// Enter the number corresponding to the desired pay rate or action:
// 1) $8.75/hr 2) $9.33/hr
// 3) $10.00/hr 4) $11.20/hr
// 5) quit
// *************************************************************
// 如果选择1~4其中的一个数字,程序应该询问用户工作的小时数。程序要通过循环运行,除非用
// 户输入5。如果输入1~5以外的数字,程序应提醒用户输入正确的选择,然后再重复显示菜单提
// 示用户输入。使用#define创建符号常量表示各工资等级和税率
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#define OVER_TIME 40.0 // 加班时数分界点
#define OVER_TIME_POWER 1.5 // 加班的时数倍率
#define GRADE_1 300.0 // 第一阶段<=300美元
#define GRADE_2 450.0 // 第二阶段300< n <= 450.0美元
#define TAX_GRADE_1 0.15 // 前300美元为15%
#define TAX_GRADE_2 0.20 // 续150美元为20%
#define TAX_GRADE_3 0.25 // 余下为25%
int main(void)
{
float hoursOfWeek, sumSalary, baseSalary, overTimePay, tax, basePerHour;
char ch = 0, c; // 选择菜单项目,清除输入缓存
bool menuSelectFail = false; // 选择失败标记
hoursOfWeek = sumSalary = baseSalary = overTimePay = tax = 0;
while (ch != '5') // 选择菜单=5时推出循环,否则进入循环
{
// 显示菜单
printf("****************************************************************\n");
printf("Enter the number corresponding to the desired pay rate or action:\n");
printf(" 1) $8.75/hr 2) $9.33/hr\n");
printf(" 3) $10.00/hr 4) $11.20/hr\n");
printf(" 5) quit\n");
printf("****************************************************************\n");
printf("Please input menu item:"); // 提示输入菜单项目
ch = getchar();
while ((c = getchar()) != EOF && c != '\n'); // 读入第一个字符并将后续缓存清空
menuSelectFail = false; // 默认菜单选择成功
switch(ch)
{
case '1':
basePerHour = 8.75; // 菜单1
break;
case '2':
basePerHour = 9.33; // 菜单2
break;
case '3':
basePerHour = 10.00; // 菜单3
break;
case '4':
basePerHour = 11.22; // 菜单4
break;
case '5':
menuSelectFail = true; // 设置菜单选择失败
break;
default:
menuSelectFail = true; // 设置菜单选择失败
printf("输入1~4选择每小时工资。输入5退出程序.\n"); // 提示并重新让选择
}
if (menuSelectFail) continue; // 如果菜单失败则进入下一轮循环
printf("输入一周工作的小时数:"); // 提示输入小时数
scanf("%f", &hoursOfWeek);
setbuf(stdin, NULL); // 清空键盘缓存
if (hoursOfWeek <= OVER_TIME)
baseSalary = basePerHour * hoursOfWeek; // 基本工资总额
else // 如果上班时数超过40小时
{
baseSalary = OVER_TIME * basePerHour; // 基本工资总额
overTimePay = (hoursOfWeek - OVER_TIME) * OVER_TIME_POWER // 加班工资总额
* basePerHour;
}
sumSalary = baseSalary + overTimePay; // 工资总额=基本工资+加班工资
if (sumSalary <= GRADE_1) // 如果在第一阶梯内则使用前300美元*15%
tax = sumSalary * TAX_GRADE_1;
else if ((sumSalary > GRADE_1) && (sumSalary <= GRADE_2)) // 如果在第二阶梯,则前300美元*20%,余下*25%
tax = GRADE_1 * TAX_GRADE_1 + (sumSalary - GRADE_1) * TAX_GRADE_2;
else // 如果在第三阶梯,则第1阶段+第2阶段+余下*25%执行
tax = GRADE_1 * TAX_GRADE_1
+ (GRADE_2 - GRADE_1) * TAX_GRADE_2
+ (sumSalary - GRADE_2) * TAX_GRADE_3;
printf("基本工资总额(小时数*基本工资): %f\n", baseSalary);
printf("加班工资总额(超出部分的小时数*倍率*基本工资): %f\n", overTimePay);
printf("工资总额(基本工资+加班工资): %f\n", sumSalary);
printf("应纳税额(税金): %f\n", tax);
printf("净收入(工资总额-税金): %f\n", sumSalary - tax);
}
return 0;
}
习题 9
// 9. 编写一个程序,只接受正整数输入,然后显示所有小于或等于该数的素数。
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
int main(void)
{
int n, i, j;
n = i = j = 0;
bool prime = false;
printf("输入一个正整数: ");
scanf("%d", &n);
if(n <= 0)
{
printf("必须输入一个正整数\n");
return 1;
}
for(i = n; i > 1; i--)
{
prime = true;
for(j = 2; j < i; j++)
{
if (i % j == 0)
{
prime = false;
break;
}
}
if(prime)
printf("%6d", j);
}
printf("\n");
return 0;
}
习题 10
// 10. 1988年美国联邦税收计划是近代最简单的税收方案。它分为4个类别,每个类别有两个等级。
// 下面是该税收计划的摘要(美元数为应征税的收入):
// ---------------------------------------------------------------------
// 类别 | 税金
// ---------------------------------------------------------------------
// 单身 | 17850美元按15%计,超出部分按28%计
// 户主 | 23900美元按15%计,超出部分按28%计
// 已婚,共有 | 29750美元按15%计,超出部分按28%计
// 已婚,离异 | 14875美元按15%计,超出部分按28%计
// ---------------------------------------------------------------------
// 例如,一位工资为20000美元的单身纳税人,应缴纳税费0.15*17850+0.28*(20000-17850)美
// 元。编写一个程序,让用户指定缴纳税金的种类和应纳税收入,然后计算税金。程序应通过循环
// 让用户可以多次输入。
#include <stdio.h>
#include <stdbool.h>
#define GRADE_1 0.15 // 第一阶梯,15%
#define GRADE_2 0.28 // 第二阶梯,28%
int main(void)
{
char ch = 0, c; // 菜单选择
bool menuSelectFail = false; // 选择失败标志
float salary, salaryGrade, tax; // 工资收入,工资等级分界线,税额
salary = salaryGrade = tax = 0; // 初始化变量
while (ch != '5') // 输入5则退出程序
{
printf("*********************************************I*************\n"); // 显示菜单
printf(" 1) 单身 17850美元按15%%计,超出部分按28%%计\n");
printf(" 2) 户主 23900美元按15%%计,超出部分按28%%计\n");
printf(" 3) 已婚,共有 29750美元按15%%计,超出部分按28%%计\n");
printf(" 4) 已婚,离异 14875美元按15%%计,超出部分按28%%计\n");
printf(" 5) 退出\n");
printf("***********************************************************\n");
printf("按1~4选择类型,按5退出: ");
scanf("%c", &ch); // 输入菜单项
while ((c = getchar()) != EOF && c != '\n'); // 读取第一个字符后,后面的字符清空
menuSelectFail = false; // 默认菜单选择有效
switch (ch) // 依据菜单选择设定不同的工资分界值
{
case '1':
salaryGrade = 17850.0;
break;
case '2':
salaryGrade = 23900.0;
break;
case '3':
salaryGrade = 29750.0;
break;
case '4':
salaryGrade = 14875.0;
break;
case '5': // 选择5,仅设置菜单选择失败
menuSelectFail = true;
break;
default: // 其他输入,提示输入失败重新输入
menuSelectFail = true;
printf("输入错误,输入1~4选择类型,按5退出\n");
}
if (menuSelectFail) continue; // 如果菜单选择失败则退出循环
printf("输入工资金额:"); // 如果税前工资
scanf("%f", &salary);
setbuf(stdin, NULL); // 清除键盘缓冲区
if (salary <= salaryGrade) // 当处于第一阶范围内,则按第一阶计算
tax = salary * GRADE_1;
else // 超过一阶则按第一阶+第二阶计算
tax = salaryGrade * GRADE_1 + (salary - salaryGrade) * GRADE_2;
printf("应纳税金额: %f\n", tax); // 输出纳税金额
printf("税后净收入: %f\n", salary - tax); // 输出净收入
}
return 0;
}
习题 11
// 11. ABC邮购杂货店出售的洋芋售价为2.05美元/磅,甜菜售价为1.15美元/磅,胡萝卜售价为1.09
// 美元磅。在添加运费之前,100美元的订单有5%的打折优惠。少于或等于5磅的订单收取6.5美
// 元的运费和包装费,5磅~20磅的订单收取14美元的运费和包装费,超过20磅的订单在14美元
// 的基础上每续重1磅增加0.5美元。编写一个程序,在循环中用switch语句实现用户输入不同
// 的字母时有不同的响应,即输入a的相应是让用户输入洋芋的磅数,b是甜菜的磅数,c是胡萝
// 卜的磅数,q是推出订购。程序要记录累计的重量。即,如果用户输入4磅的甜菜,然后输入5
// 磅的甜菜,程序应报告9磅的甜菜。然后,该程序要计算货物总价、折扣(如果有的话)、运费和
// 包装费。随后,程序应显示所有的购买信息:物品售价、订购的重量(单位:磅)、订购的蔬菜费
// 用,订单的总费用、折扣(如果有的话)、运费和包装费,以及所有的费用总额。
#include <stdio.h>
#include <stdbool.h>
#define ITEM_PRICE_1 2.05 // 洋芋每磅单价
#define ITEM_PRICE_2 1.15 // 甜菜每磅单价
#define ITEM_PRICE_3 1.09 // 胡萝卜每磅单价
void showMenu(void); // 显示菜单
float packingCharges(float weight); // 包装费+运费
float discount(float pay); // 计算折扣
int main(void)
{
float fDiscount, fPay, fPacking, fSumWeight, weight;
float fWeightItem1, fWeightItem2, fWeightItem3;
float fPayItem1, fPayItem2, fPayItem3;
bool selectMenuFail;
char ch = 0, c;
fWeightItem1 = fWeightItem2 = fWeightItem3 = 0; // 初始化变量
fPayItem1 = fPayItem2 = fPayItem3 = 0;
while (ch != 'q') // 如果输入字符是q则立即退出程序
{
showMenu(); // 显示菜单
printf("请选择购买的商品(a,b,c),按(q)退出:");
scanf("%c", &ch); // 读入菜单选择项目
while ((c = getchar()) != EOF && c != '\n'); // 读取第一个字符后,后面的字符清掉
selectMenuFail = false;
switch (ch)
{
case 'a': // 选择洋芋
printf("请输入购买商品的重量(单位:磅):");
scanf("%f", &weight);
setbuf(stdin, NULL); // 清除键盘缓冲区
fWeightItem1 = fWeightItem1 + weight;
fPayItem1 = fWeightItem1 * ITEM_PRICE_1;
break;
case 'b': // 选择甜菜
printf("请输入购买商品的重量(单位:磅):");
scanf("%f", &weight);
setbuf(stdin, NULL); // 清除键盘缓冲区
fWeightItem2 = fWeightItem2 + weight;
fPayItem2 = fWeightItem2 * ITEM_PRICE_2;
break;
case 'c': // 选择胡萝卜
printf("请输入购买商品的重量(单位:磅):");
scanf("%f", &weight);
setbuf(stdin, NULL); // 清除键盘缓冲区
fWeightItem3 = fWeightItem3 + weight;
fPayItem3 = fWeightItem3 * ITEM_PRICE_3;
break;
case 'q':
selectMenuFail = true;
break;
default:
selectMenuFail = true;
printf("输入错误,请选择购买的商品(a,b,c),按(q)退出\n");
}
if (selectMenuFail) continue; // 如果菜单选择失败则忽略并重新显示菜单
fPay = fPayItem1 + fPayItem2 + fPayItem3; // 金额合计=洋芋金额+甜菜金额+胡萝卜金额
fSumWeight = fWeightItem1 + fWeightItem2 + fWeightItem3; // 总重量=洋芋重量+甜菜重量+胡萝卜重量
fDiscount = discount(fPay); // 计算折扣
fPacking = packingCharges(fSumWeight); // 计算包装及运费
printf("------------ 采购清单如下 -----------------\n");
printf(" a. 洋芋 金额: %10.2f 重量: %10.2f磅\n", fPayItem1, fWeightItem1);
printf(" b. 甜菜 金额: %10.2f 重量: %10.2f磅\n", fPayItem2, fWeightItem2);
printf(" c. 胡萝卜 金额: %10.2f 重量: %10.2f磅\n", fPayItem3, fWeightItem3);
printf("--------------------------------------------\n");
printf("合计: 金额(+): %10.2f 重量: %10.2f磅\n", fPay, fSumWeight); // 输出结算
printf("-----------折扣(-): %10.2f\n", fDiscount);
printf("-----------运费(+): %10.2f\n", fPacking);
printf("----------应付总额: %10.2f\n", fPay - fDiscount + fPacking);
}
return 0;
}
void showMenu(void)
{
printf("************* menu *******************\n");
printf(" a) 洋芋 $2.05/pound\n");
printf(" b) 甜菜 $1.15/pound\n");
printf(" c) 胡萝卜 $1.09/pound\n");
printf(" q) 退出\n");
printf("****************************************\n");
}
float discount(float pay)
{
return (int)(pay / 100) * (100.0 * 0.05);
}
float packingCharges(float weight)
{
if (weight <= 5.0)
return 6.5;
else if (weight > 5.0 && weight <= 20)
return 14.0;
else
return 14.0 + (weight - 20.0) * 0.5;
}