第八章所讲的I/O、重定向以及创建更友好的用户界面都是曾经的C语言课堂上没有系统讲解过的,其中,I/O和重定向是我第一次接触,个人觉得重定向所做的工作和stdlib里对文件处理的一系列函数所做的工作很类似。而创建更友好的用户界面虽然我才刚刚学到,但是看过前几章答案的朋友应该能注意到我已经开始考虑这些问题了,也算是查漏补缺,完善自我。下面跟大家分享第8章的编程练习答案,
1.设计一个程序,统计在读到文件结尾之前读取的字符数。
参考代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main(void)
{
int ch = 0, count = 0;
printf("请输入字符, 我将为您统计所读到的字符数(输入Ctrl + Z 结束):");
while ((ch = getchar()) != EOF)
{
count++;
}
printf("我所统计到的字符数为:%d", count);
return 0;
}
参考结果如下:
2.编写一个程序,在遇到EOF 之前,把输入作为字符流读取。程序要打印每个输入的字符及其相应的ASCII 十进制值。注意,在ASCII 序列中,空格字符前面的字符都是非打印字符,要特殊处理这些字符。如果非打印字符是换行符或制表符,则分别打印\n 或\t 。否则,使用控制字符表示法。例如,ASCII 的1是Ctrl+A,可显示为^A 。注意,A 的ASCII值是Ctrl+A 的值加上64。其他非打印字符也有类似的关系。除每次遇到换行符打印新的一行之外,每行打印10对值。(注意:不同的操作系统其控制字符可能不同。)
参考代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define SIZE 500
int main(void)
{
int ch[SIZE] = { 0 }, count = 0, i = 0;
printf("请输入字符, 我将为您统计所读到的字符数(输入Ctrl + Z 结束):");
while ((ch[i] = getchar()) != EOF)//将用户输入的所有字符储存在ch数组中,以便后续按规定的格式打印
{
i++;
}
printf("您输入的字符及对应的ASCII码为:\n");
for (i = 0; ch[i] != EOF; i++)
{
if (ch[i] == '\n')
{
printf("\\n-%-8.d ", ch[i]);
}
else if (ch[i] == '\t')
{
printf("\\t-%-8.d ", ch[i]);
}
else
printf("%c-%-8.d ", ch[i], ch[i]);
count++;
if (count == 10)
{
printf("\n");
count = 0;
}
}
printf("\n程序结束!感谢您的使用!\n");
return 0;
}
参考结果如下:
注:本题的难点在于读取数据时是否要去掉用户输入的ENTER,以及后续排版问题。
3.编写一个程序,在遇到 EOF 之前,把输入作为字符流读取。该程序要报告输入中的大写字母和小写字母的个数。假设大小写字母数值是连续的。或者使用 ctype.h 库中合适的分类函数更方便。
参考代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int ch = 0, uc_num = 0, lc_num = 0;
printf("请输入字符,我将为您统计大写字母和小写字母的个数(输入Ctrl+Z结束):");
while ((ch = getchar()) != EOF)
{
if (ch >= 'a' && ch <= 'z')
{
lc_num++;
}
else if (ch >= 'A' && ch <= 'Z')
{
uc_num++;
}
else
continue;
}
printf("您好!您所输入的大写字母的个数为:%d,小写字母的个数为:%d", uc_num, lc_num);
return 0;
}
参考结果如下:
4.编写一个程序,在遇到 EOF 之前,把输入作为字符流读取。该程序要报告平均每个单词的字母数。不要把空白统计为单词的字母。实际上,标点符号也不应该统计,但是现在暂时不同考虑这么多(如果你比较在意这点,考虑使用ctype.h 系列中的ispunct() 函数)。
参考代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int ch = 0, letter_num = 0, word_num = 0, mark_1 = 0;
float con = 0;
printf("请输入字符,我将为您统计平均每个单词的字母数(输入Ctrl+Z结束):");
while ((ch = getchar()) != EOF)
{
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')
{
letter_num++;
mark_1 = 1;
}
else if (mark_1 == 1)
{
word_num++;
mark_1 = 0;
}
else
continue;
}
printf("您好!您所输入的单词数为:%d,平均每个单词的字母数为:%.1f\n", word_num, (float)letter_num / (float)word_num);
return 0;
}
参考结果如下:
5.修改程序清单8.4的猜数字程序,使用更智能的猜测策略。例如,程序最初猜50,询问用户是猜大了、猜小了还是猜对了。如果猜小了,那么下一次猜测的值应是50 和100 中值,也就是75 。如果这次猜大了,那么下一次猜测的值应是50 和75的中值,等等。使用二分查找 (binary search )策略,如果用户没有欺骗程序,那么程序很快就会猜到正确的答案。
参考代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define MAX_1 10000
#define MIN_1 0
#define MAX_2 0
#define MIN_2 -10000
int main(void)
{
char ans = 0;
int num, min_1 = MIN_1, max_1 = MAX_1, min_2 = MIN_2, max_2 = MAX_2, mark_1 = 0, mark_2 = 0;
printf("嘿,我们来玩一个游戏吧!请在心中选择一个-10000到10000之间的整数,我来猜猜这个数字是多少\n");
printf("如果我猜大了,请您输入b,如果我猜小了,请您输入s\n");
printf("当然,如果我猜对了,请您输入y\n");
printf("输入Ctrl+Z退出程序\n");
printf("请问这个数是0吗?\n");
while ((ans = getchar()) != EOF)
{
switch (ans)
{
case 's'://处理大于零的情况
num = 5000;
printf("请问这个数是%d吗?\n", num);
while (getchar() != '\n')//处理用户输入的ENTER
continue;
while ((ans = getchar()) != EOF)//通过二分法迭代来猜用户的数字
{
while (getchar() != '\n')//处理用户输入的ENTER
continue;
switch (ans)
{
case 'b':
if (mark_1 == 0 && mark_2 == 0)
{
max_1 = 5000;
mark_1 = 1;//标志一,作用是将max_1初始化一次
}
max_1 = num;
num = (min_1 + max_1) / 2;
printf("请问这个数是%d吗?\n", num);
continue;
case 's':
if (mark_2 == 0 && mark_1 == 0)
{
min_1 = 5000;
mark_2 = 1;
}//标志二,作用是将min_1初始化一次
min_1 = num;
num = (min_1 + max_1) / 2;
printf("请问这个数是%d吗?\n", num);
continue;
case'y':
printf("耶耶耶!原来是%d呀,我还是挺厉害的嘛,能陪我玩这么无聊的游戏的也很厉害!谢谢你!\n", num);
break;
default:
if (ans != 'y' && ans != 's' && ans != 'b')
printf("只能输入s(small)、b(big)和y(yes)哦!\n");
continue;
}
break;
}
break;
case 'b'://处理小于零的情况
num = -5000;
printf("请问这个数是%d吗?\n", num);
while (getchar() != '\n')//处理用户输入的ENTER
continue;
while ((ans = getchar()) != EOF)//通过二分法迭代来猜用户的数字
{
while (getchar() != '\n')//处理用户输入的ENTER
continue;
switch (ans)
{
case 'b':
if (mark_1 == 0 && mark_2 == 0)
{
max_2 = -5000;
mark_1 = 1;
}
max_2 = num;
num = (min_2 + max_2) / 2;
printf("请问这个数是%d吗?\n", num);
continue;
case 's':
if (mark_2 == 0 && mark_1 == 0)
{
min_2 = -5000;
mark_2 = 1;
}
min_2 = num;
num = (min_2 + max_2) / 2;
printf("请问这个数是%d吗?\n", num);
continue;
case 'y':
printf("耶耶耶!原来是%d呀,我还是挺厉害的嘛,能陪我玩这么无聊的游戏的也很厉害!谢谢你!\n", num);
break;
default:
if (ans != 'y' && ans != 's' && ans != 'b')
printf("只能输入s(small)、b(big)和y(yes)哦!\n");
while (getchar() != '\n')//处理用户输入的ENTER
continue;
continue;
}
break;
}
break;
case 'y':
printf("哇塞,我还以为您会出一些更难的数字呢,谢谢您的使用!\n");
break;
default:
if (ans != 'y' && ans != 's' && ans != 'b')
printf("只能输入s(small)、b(big)和y(yes)哦!\n");
while (getchar() != '\n')//处理用户输入的ENTER
continue;
continue;
}
break;
}
return 0;
}
参考结果如下:
注:本题有几个难点:1、要处理用户输入错误,并让其重新输入。2、要处理用户输入的ENTER。3、二分法在程序里如何实现需要去考虑。
6.修改程序清单8.8中的get_first() 函数,让该函数返回读取的第1个非空白字符,并在一个简单的程序中测试。
参考代码如下:
#include<stdlib.h>
char get_first(void);
int main(void)
{
int ch = 0;
printf("本程序的作用为返回用户输入的第一个非空白字符,并打印这个字符:");
ch = get_first();
printf("我所读取到的第一个非空白字符为:%c", ch);
return 0;
}
char get_first(void)
{
int ch = 0, mark_1 = 0, mark_2 = 0;
do {
ch = getchar();
if (ch == '\n')
printf("请至少输入一个非空白字符:\n");//一开始我认为要用标记变量来控制程序只打印一个提醒,后面发现用户输入是以ENTER结尾的,只需要判断用户是否输入了enter就好了。
} while (ch == '\n' || ch == ' ' || ch == '\t' || ch == '\r' || ch == '\f' || ch == '\v');
return ch;
}
参考结果如下:
注意:一开始我认为要用标记变量来控制程序只打印一个提醒,后面发现用户输入是以ENTER结尾的,只需要判断用户是否输入了enter就好了。
7.修改第7章的编程练习8,用字符代替数字标记菜单的选项。用q 代替5作为结束输入的标记。
参考代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define BASETIME 40
#define OVERTIME_SALARY 15
#define SALARY_LEVEL_1 8.75
#define SALARY_LEVEL_2 9.33
#define SALARY_LEVEL_3 10.00
#define SALARY_LEVEL_4 11.20
int main(void)
{
const float F_TAX = 0.15;
const float S_TAX = 0.20;
const float T_TAX = 0.25;
char level = 0;
float hour = 0.0, salary = 0.0, tax = 0.0, income = 0.0, base_salary = 0.0;
printf("***************************************************\n");
printf("现有以下几个工资等级供您选择(选择字母q结束程序):\n");
printf("当您输入多个字符时,我只会读取第一个非空白字符\n");
printf("a) $8.75/hr b) $9.33/hr\nc) $10.00/hr d) $11.20/hr\nq) quit\n");
printf("***************************************************\n");
printf("请输入输入字母以选择您的工资等级:");
while ((level = getchar()) != 'q')
{
while (getchar() != '\n')//消除空白字符
continue;
switch (level)
{
case 'a':
base_salary = SALARY_LEVEL_1;
break;
case 'b':
base_salary = SALARY_LEVEL_2;
break;
case 'c':
base_salary = SALARY_LEVEL_3;
break;
case 'd':
base_salary = SALARY_LEVEL_4;
break;
case 'q':
break;
default:
printf("错误,请您重新选择:\n");
continue;
}
break;
}
if (level != 'q')
{
printf("请输入您一周工作的小时数:");
while (scanf("%f", &hour) != 1)
{
printf("出错啦,请输入数字:");
while (getchar() != '\n')//消除空白字符
continue;
continue;
}
}
if (hour <= BASETIME && level != 'q')
{
salary = base_salary * hour;
if (salary <= 300)
{
tax = salary * F_TAX;
income = salary - tax;
printf("您的工资总额为:%.2f,税金为:%.2f,净收入为:%.2f", salary, tax, income);
}
else
{
tax = 300 * F_TAX + (salary - 300) * S_TAX;
income = salary - tax;
printf("您的工资总额为:%.2f,税金为:%.2f,净收入为:%.2f", salary, tax, income);
}
}
if (hour > BASETIME && level != 'q')
{
salary = base_salary * BASETIME + OVERTIME_SALARY * (hour - BASETIME);
if (salary <= 450)
{
tax = 300 * F_TAX + (salary - 300) * S_TAX;
income = salary - tax;
printf("您的工资总额为:%.2f,税金为:%.2f,净收入为:%.2f", salary, tax, income);
}
else
{
tax = 300 * F_TAX + 150 * S_TAX + (salary - 450) * T_TAX;
income = salary - tax;
printf("您的工资总额为:%.2f,税金为:%.2f,净收入为:%.2f", salary, tax, income);
}
}
printf("\n程序结束,感谢您的使用!\n");
return 0;
}
参考结果如下:
注:此题无太多难度,仅需预先考虑到用户输入的各种情况。
8.编写一个程序,显示一个提供加法、减法、乘法、除法的菜单。获得用户选择的选项后,程序提示用户输入两个数字,然后执行用户刚才选择的操作。该程序只接受菜单提供的选项。程序使用float 类型的变量储存用户输入的数字,如果用户输入失败,则允许再次输入。进行除法运算时,如果用户输入0 作为第2个数(除数),程序应提示用户重新输入一个新值。该程序的一个运行示例如下:
Enter the operation of your choice:
a. add s. subtract
m. multiply d. divide
q. quit
a
Enter first number: 22 .4
Enter second number: one
one is not an number.
Please enter a number, such as 2.5, -1.78E8, or 3: 1
22.4 + 1 = 23.4
Enter the operation of your choice:
a. add s. subtract
m. multiply d. divide
q. quit
d
Enter first number: 18.4
Enter second number: 0
Enter a number other than 0: 0.2
18.4 / 0.2 = 92
Enter the operation of your choice:
a. add s. subtract
m. multiply d. divide
q. quit
q
Bye.
参考代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
void caculate(int ch);
int main(void)
{
int ch = 0;
printf("**************************************************\n");
printf("这是一个简单的计算器,请根据输入字母选择相应的功能\n");
printf("a.加法(+) s.减法(-)\nm.乘法(×) d.除法(÷)\nq.退出程序\n");//菜单
printf("**************************************************\n");
printf("您的选择是:");
while ((ch = getchar()) != 'q')
{
while (getchar() != '\n')
continue;
switch (ch)
{
case 'a':
caculate(ch);
continue;
case 's':
caculate(ch);
continue;
case 'm':
caculate(ch);
continue;
case 'd':
caculate(ch);
continue;
case 'q':
break;
default:
printf("错误,请重新选择:\n");
printf("**************************************************\n");
printf("这是一个简单的计算器,请根据输入字母选择相应的功能\n");
printf("a.加法(+) s.减法(-)\nm.乘法(×) d.除法(÷)\nq.退出程序\n");//菜单
printf("**************************************************\n");
printf("您的选择是:");
continue;
}
break;
}
printf("程序结束,感谢您的使用!\n");
return 0;
}
void caculate(int ch)
{
float num_1 = 0.0, num_2 = 0.0, result = 0.0;
printf("请输入第一个数字:");
while (scanf("%f", &num_1) != 1)
{
printf("错误,请输入数字:");
while (getchar() != '\n')//消除空白字符
continue;
continue;
}
printf("请输入第二个数字:");
while (scanf("%f", &num_2) != 1)
{
printf("错误,请输入数字:");
while (getchar() != '\n')//消除空白字符
continue;
continue;
}
switch (ch)
{
case 'a':
result = num_1 + num_2;
printf("%.2f + %.2f = %.2f\n", num_1, num_2, result);
break;
case 's':
result = num_1 - num_2;
printf("%.2f - %.2f = %.2f\n", num_1, num_2, result);
break;
case 'm':
result = num_1 * num_2;
printf("%.2f × %.2f = %.2f\n", num_1, num_2, result);
break;
case 'd':
result = num_1 / num_2;
printf("%.2f ÷ %.2f = %.2f\n", num_1, num_2, result);
break;
}
printf("计算完毕,请重新选择:");
while (getchar() != '\n')//消除空白字符
continue;
}
参考结果如下:
注意:
while(getchar() != '\n')
continue;
这真的是一段很有用的代码,对于消除用户输入的ENTER,避免影响后续输入真的很有效果,但是,使用是一定要注意放对地方,不可滥用。