【从问题到程序--裘宗燕--课后习题部分答案】
第二章
练习
1. 指出下面的哪些字符序列不是合法的标识符: _abc x+- 3x1 Xf_1__4 Eoof___ x__x__2 ____ I am 答:不合法的标示符有: a$#24 非法符号# x+- 非法符号#
3x1 不是以英文字母开头 I am 非法符号“空格” bg--1 非法符号-
2. 手工计算下列表达式的值: 1)125 + 0125 2)0XAF - 0XFA
3)24 * 3 / 5 + 6 4)36 + - (5 - 23) / 4 5)35 * 012 + 27 / 4 / 7 * (12 - 4)
答:1)210 2)-75 3)20 4)40 5)350
3. 在下面表达式的计算过程中,在什么地方将发生类型转换,各个转换是从什么类型转换 到什么类型,表达式计算的结果是什么? 1)3 * (2L + 4.5f) - 012 + 44
2)3 * (int)sqrt(34) - sin(6) * 5 + 0x2AF 3)cos(2.5f + 4) - 6 *27L + 1526 - 2.4L
答:1)53.5 2)703.397077 在此题中十六进制数会在计算中(编译时)自动转成十进制数 3)1362.59357
4. 写程序计算第3 题中各个表达式的值。 答:
#include #include
int main(){
printf("%f\n",3 * (2L + 4.5f) - 012 + 44);
printf("%f\n",3 * (int)sqrt(34) - sin(6) * 5 + 0x2AF); printf("%f\n",cos(2.5f + 4) - 6 *27L + 1526 - 2.4); system("pause"); return 0; }
5. 写程序计算下面各个表达式的值: 1) 2 34
1 257 .
+ 2) 1065 24*13
3) 23 582
7 96 3 67 .
. / . 4)
π2 +1 7)ln ln(10 1) 2π +
5)log5 2π −1 6)e π +1 7)arctan(log ( )) 3 e + π 8) 3.68
13−(2.24−0.242 )2 9)3 4 5
1 2
+ + / 10)ln(2π 13+ e )
6. 已知铁的比重是7.86,金的比重是19.3。写几个简单程序,分别计算出直径100 毫米和 150 毫米的铁球与金球的重量。 答:
#include
double f1(double r){ double v,w;
v=4.0/3.0*r*r*r*3.1415926; w=7.86*v; return w; }
double f2(double r){ double v,w;
v=4.0/3.0*r*r*r*3.1415926; w=19.3*v; return w; }
int main(){
printf("铁球的重量为: %f,金球的重量为: %f\n",f1(0.1/2),f2(0.1/2.0)); printf("铁球的重量为: %f,金球的重量为: %f\n",f1(0.15/2),f2(0.15/2.0)); system("pause"); return 0; }
2
7. 写程序计算 5x + 2x + 6 的两个根,考虑用合适的方式输出。(提示:对这个具体问题,可以先人工计算
2
出判别式 b− 4ac 的值,以此作为已知信息,就可以写出程序
了。) 答:
#include #include
void f(double a,double b,double c){ double temp=b*b-4*a*c;
if(temp>0)
printf("方程的根为:%f,%f",(-b+sqrt(temp))/2/a,(-b-sqrt(temp))/2/a); else if(temp==0)
printf("方程有两个相同的根为:%f",-b/2/a); else
printf("方程无解!"); }
int main(){
f(5,2,6); //可以测试不同的数据 system("pause"); return 0; }
8. 在计算机上试验本章正文中的一些程序。对它们做一些修改,观察程序加工和运行的情 况,并对程序的行为做出解释。
9. 在一个能正确工作工作的输出整数结果的程序里,将printf 的相应转换描述改为 %f 或者 %ld,看看会出现什么问题。在一个能正确工作工作的输出双精度结果的程序里, 1、 将printf 的相应转换描述改为 %d 或者 %ld,看看会出现什么问题。
第三章
练习
1. 下面的字符序列中哪些不是合法的变量名: -abc __aa for pp.288 IBM/PC tihs
While r24_s25 __a__b a"bc _345 答:
-abc for pp.288 to be IBM/PC ms-c #micro m%ust While a"bc
2. 假设整型变量a 的值是1,b 的值是2,c 的值是3,在这种情况下分别执行下 面各个语句,写出执行对应语句后整型变量u 的值。 1) u = a ? b : c;
2) u = (a = 2) ? b + a : c + a; 答:
1)u=2 2)u=4
3. 假设整型变量a 的值是1,b 的值是2,c 的值是0,写出下面各个表达式的值。 1) a && !((b || c) && !a)
2) !(a && b) || c ? a || b : a && b && c 3) !(a + b
1)1 2)0 3)0
4. 下面程序在执行时,哪些地方将发生类型转换?程序打印的值是什么?
int f (int n, float m) { return (m + n) / 4;
}
int main () { float y = 3;
printf("%d\n", f(y, y + 1)); return 0; }
答:
{
}
}
5. 在计算机上试验本章正文中的一些程序。对它们做一些修改,观察程序加工和运行的情 况,并对程序的行为做出解释。 答案:略
6. 定义求圆球的体积、求圆球的表面积、求圆柱体的体积、求圆柱体的表面积的函数。 答:
#include double f1(double r){ double v;
v=4.0/3.0*r*r*r*3.1415926; return v; }
double f2(double r){ double s;
s=4*r*r*3.1415926; return s; }
double f3(double r,double h){ double v;
v=r*r*3.1415926*h; return v; }
double f4(double r,double h){ double s;
s=2*3.1415926*r*h+2*3.1415926*r*r; return s; }
int main(){
printf("圆球的体积为%f\n",f1(0.15)); printf("圆球的面积为%f\n",f2(0.15));
printf("圆柱体的体积为%lf\n",f3(0.15,0.5)); printf("圆柱体的面积为%lf\n",f4(0.15,0.5)); system("pause"); return 0; }
7. 1)不用函数,直接写一个主程序计算并输出直径为100 毫米和150 毫米的金、银、铜、 铁、锡球的重量(以kg 为单位输出)。
2)重新完成上面程序,先定义一个带有两个参数的函数,它能求出直径为x 的比重为 y 的圆球的重量,而后在主程序里调用这个函数完成所需工作。将这样得到的解与不用 函数的解比较,比较它们的长度、容易出错的程度。假设现在要求修改所用圆周率的精 度,考虑用两种方式写程序的修改难度。
3)请写程序,求出边长为100 毫米和150 毫米的金、银、铜、铁、锡立方体的重量。 你可以利用前面的程序吗?是否很容易修改前面程序,完成这一计算?比较不用函数的 解法和使用函数的解法在易修改和重复使用方面的效用。
8. 定义函数:double tmax(double, double, double),它返回三个参数中最大的 一个。写一个主函数试验各种参数情况。 答:
#include
double tmax(double x,double y,double z){ if(x>y)
#include
double f1(double r){
double v;
v=4.0/3.0*r*r*r*3.1415926;
return v;
}
double f2(double r){
double s;
s=4*r*r*3.1415926;
return s;
}
double f3(double r,double h){
double v;
v=r*r*3.1415926*h;
return v;
}
double f4(double r,double h){
double s;
s=2*3.1415926*r*h+2*3.1415926*r*r;
return s;
}
int main(){
printf("圆球的体积为%f\n",f1(0.15));
printf("圆球的面积为%f\n",f2(0.15));
printf("圆柱体的体积为%lf\n",f3(0.15,0.5));
printf("圆柱体的面积为%lf\n",f4(0.15,0.5));
system("pause");
return 0;
}
7. 1)不用函数,直接写一个主程序计算并输出直径为100 毫米和150 毫米的金、银、铜、
铁、锡球的重量(以kg 为单位输出)。
2)重新完成上面程序,先定义一个带有两个参数的函数,它能求出直径为x 的比重为
y 的圆球的重量,而后在主程序里调用这个函数完成所需工作。将这样得到的解与不用
函数的解比较,比较它们的长度、容易出错的程度。假设现在要求修改所用圆周率的精
度,考虑用两种方式写程序的修改难度。
3)请写程序,求出边长为100 毫米和150 毫米的金、银、铜、铁、锡立方体的重量。
你可以利用前面的程序吗?是否很容易修改前面程序,完成这一计算?比较不用函数的
解法和使用函数的解法在易修改和重复使用方面的效用。
8. 定义函数:double tmax(double, double, double),它返回三个参数中最大的
一个。写一个主函数试验各种参数情况。
答:
#include
double tmax(double x,double y,double z){
if(x>y)
return x>z?x:z;
else
return y>z?y:z;
}
int main(){
printf("最大的一个为:%f",tmax(8,3,2));
printf("最大的一个为:%f",tmax(8,13,2));
printf("最大的一个为:%f",tmax(8,3,22));
system("pause");
return 0;
}
9. 写函数,它以两个电阻的值作为参数,求出并联的电阻值。
答:并联电阻值的计算公式为:R1*R2/(R1+R2)
10. 如果四边形四个边的长度分别为a、b、c、d ,一对对角之和为2α ,则其面积为:
S = (s − a)(s − b)(s − c)(s − d ) − abcd cos2α
其中s =(a + b + c + d)/2。
定义一个函数计算任意四边形的面积。设有一个四边形,其
四条边边长分别为3、4、5、5,一对对角之和为145o ,写程序计算它的面积。
11. 修改已知四边长求四边形面积的函数,增加对各种参数错误情况的检查和处理(如返回
值0),用各种实例数据检查你的函数否检查出所有可能的错误情况。
12. 分析本章正文中给出的求二次方程根的函数,看它缺乏对哪些特殊情况的处理。补充这
些处理,在需要时输出适当的信息,使之成为一个更完整的函数。写一个主函数,用各
种特殊情况和一般情况测试所完成的函数。
答:
#include
#include
void f(double a,double b,double c){
double temp=b*b-4*a*c;
if(a==0)printf("方程的根为:%f",-c/b);
if(temp>0)
printf("方程的根为:%f,%f",(-b+sqrt(temp))/2/a,(-b-sqrt(temp))/2/a);
else if(temp==0)
printf("方程有两个相同的根为:%f",-b/2/a);
else
printf("方程无解!");
}
int main(){
f(5,2,6); //可以测试不同的数据
system("pause");
return 0;
}
13. 写一个简单程序,它输出从1 到10 的整数。
14. 写一个简单程序,它输出从10 到-10 的整数。
15. 写一个两个整型参数的简单函数,它输出从第一个整数到第二个整数为止的整数序列。
16. 用定义函数double power(double x, int n),它求出x 的n 次幂。用主函数试
验很大的n 值(例如令x 值为1),看看会出现什么情况;用大的x 和n 值,看看发生
浮点数计算溢出时会出现什么情况。
17. 写一个程序,它在0~90 度之间每隔5 度输出一行数据,打印一个表。每行中包括5 个
项目:角度数,以及它所对应的正弦、余弦、正切、余切函数值。
答:
#include
#include
int main(){
double s=0*3.1415926/180;
int i;
for(i=0;i
printf("%f ,%f ,%f ,%f ,%f\n",s,sin(s),cos(s),tan(s),1/tan(s));
s+=5*3.1415926/180;
}
system("pause");
return 0;
}18. 查看有关公式,写求解并输出一元三次方程的根的函数。
19. 写出求等差级数的和 ka k
n
= Σ 1
的函数。两种循环结构给出函数定义,再利用等差级数求和公式给出函数定义。
答:
#include
double f1(int n,double a){
int i;
double sum=0;
for(i=1;i
sum+=i*a;
return sum;
}
double f2(int n,double a){
int i=1;
double sum=0;
while(i
sum+=i*a;
++i;}
return sum;
}
double f3(int n,double a){
return n*(a+n*a)/2;
}
int main(){
printf("%f\n",f1(10,2.5));
printf("%f\n",f2(10,2.5));
printf("%f\n",f3(10,2.5));
system("pause");
return 0;
}
20. 请到查出银行一年定期存款的利率和5 年定期存款的利率。假定现在要存入100 元钱,
存款到期后立即将利息与本金一起再次存入。请写出程序,计算按每次存一年和按照每
次存5 年,总共存50 年后两种存款方式的得款总额。对两种情况都每隔5 年输出一次
当时的总金额。
21. 写一个程序打印出2 的顺序各次幂。让它打印出2 的前30 个幂,看看会出现什么情况。
用一个条件为真的循环打印2 的各次幂,看看会出现什么情况。
第四章
练习
1. 1)写出通过递推方式求200之内的完全平方数的程序;2)写出只使用加法的求完全平方数的程序;3)写出求1000之内的完全立方数的程序,请参考书中实例的写法和上面的两种写法,分别写出相应的求立方数的版本。
2. 试验正文中乌龟旅行的实例,看看在你所用的C系统上得到什么样的结果。从数学教科书中找出有关调和级数的理论结论,并将它与我们的试验做一个比较。
3. 写一个程序,计算并输出Fibonacci序列中一系列的相邻项之比。确定一个范围,观察输出的结果,能够得到什么结论(这个比的序列可能有极限吗?极限是什么)。查阅有关资料,了解有关的理论结果。
4. 写函数计算 1! + 2! + ... + k!。用主函数试验函数对一系列k值计算出的结果。你写出的函数对1到10计算结果都正确吗?如果出现错误,弄清楚是什么原因。这个程序能对k = 30得到正确结果吗?(另外,你能只用一重循环完成函数的定义吗?)
5. 写函数计算:
答:
#include
#include
double f(int n,double x){
int m=0;
double sum;
for(sum=1+1/x;m
sum=1+1/sum;
return sum;
}
int main(){
int x;
,公式中有n层嵌套。利用这 L
for(x=1;x
printf("%f\n",f(10,(double)x));
}
system("pause");
return 0;
}
个函数打印 x = 1.0、2.0、„、20.0,n = 10时的函数值表。
6. 实现书中讨论的验证哥德巴赫猜想的程序,用不同的n对 6~n 的范围试验该程序。去掉程序中的打印输出语句,增加计时功能,对不同的n运行程序,考察程序的运行时间,画出一条曲线,说明运行时间与n的关系。
7. 设法(从文献中)找到其他更有效的素数判断方法并实现对应函数。在一个数值比较大的整数区间试验书上给出的函数和你写的其他函数,利用它们打印出这一区间中的所有素数。你所试验的几种方法在工作效率上有明显差异吗?(为程序计时)
8.1) 定义函数:void prt_factors(int),它对正整数实参输出其所有的因子。
2)定义函数:void prt_pfactors(int),它对正整数实际参数,输出其所有的素因子(多重因子重复输出);对于负参数,首先输出-1,然后输出所有因子。
9. 已知,利用该公式编程序求 π 的近似值,看用这个和式的前多少项求出的近似值与
3.14159165的误差小于1e-5,令程序输出三项数据:计算得到的和,由这个和求出的的近似值,求得该和所用得项数。把 1e-6\1e-7 并重新试验,用计时方式总结出误差减小与执行时间之间的关系。
答:
#include
#include
#include
int main(){
double a=3.14159265*3.14159265/6.0;
double x=1.0,n=2.0;
double t;
t=clock();
while(fabs(a-x)>1e-8){
x=x+1/n/n;
++n;
}
double pi=sqrt(6.0*x);
printf("n=%f,%f,%.32f\n",n,x,pi);
printf("%fs\n",(clock()-t)/CLOCKS_PER_SEC);
system("pause");
return 0;
}
11. 修改书中计算sin值的函数,使之能输出计算中循环执行的次数。用不同的数值(一个比一个大)试验这一函数,观察出现的情况。你看到出现溢出的情况了吗?(为试验方便,你应该写一个适用的驱动程序)
12. 已知−⋅⋅⋅⋅⋅⋅=−⋅+⋅−⋅+[***********]7xxxxxL−1x
sinh(x
13. 考虑不用函数(例如isprime)直接写出对6~200的偶数验证哥德巴赫猜想的程序(利用循环、条件、peak语句等,不使用goto语句)。将这样写出的程序与用定义函数的方式写出的程序比较。例如考察两个函数的行数、
字节数,其中各种控制结构的嵌套深度,控制结构使用的个数等。
14. 辗转相减求最大公约数的递归定义是(其中m>0, n>0)
:
利用这个定义,用递归和循环方式各写出一个求最大公约数的函数。
答://--辗转相减求最大公约数
#include
int gcd(int m,int n){
return m==n?m:(m
}
int main(){
printf("%d\n",gcd(96,56));
system("pause");
return 0;
}
15. 对一些n值试验河内塔程序,给它们计时。据此估计你所用的计算机搬完64个金盘需要多长时间。如果僧侣们1秒钟搬金盘1次,搬完64个金盘需要多少时间?将这一时间与科学家对宇宙的估计寿命做个比较,据此评价僧侣们的说法。
16. 一个三位的十进制整数,如果它的三个数位数字的立方和等于这个数的数值,那么它就被称为一个“水仙花数”。定义函数判断一个整数是水仙花数,并利用这个函数打印出所有的水仙花数。
答:
//——求水仙花数
//方法一
#include
void f(int n){
int i,j,k;
i=n/100;
j=(n-i*100)/10;
k=n-i*100-j*10;
if(i*i*i+j*j*j+k*k*k==n)
printf("%d=%d^3+%d^3+%d^3\n",n,i,j,k);
else ;
}
int main(){
int i;
for(i=100;i
f(i);
system("pause");
return 0;
//方法二
void f(){
int i,j,k,x;
for(i=1;i
for(j=0;j
for(k=0;k
{ x=i*i*i+j*j*j+k*k*k;
if(x==i*100+j*10+k)
printf("%d=%d^3+%d^3+%d^3\n",x,i,j,k);
}
}
int main(){
f();
system("pause");
return 0;
}
17. 对一个整数,如果其所有因子(包括因子1在内)之和正好等于这个数,那么就称它为“完全数”。因子之和小于自身的数称为“亏数”;因子之和大于自身的数称为“盈数”。写一个函数,当其参数是亏数时返回负值,是完全数时返回0,是盈数时返回正值。利用这个函数求出1000以内的所有完全数(实际上只有1、6、28、496)。为这个程序计时:从100开始每隔100做一次计算,写一个循环,输出各次计算花的时间。再从1000开始,每隔1000做一次计算直到10000为止,输出对程序执行计时的值。利用所定义的函数对一段区间的整数做一个分类,输出其中各个数所属的类。
18. 写程序由标准输入得到一系列三个一组的数,把每组数作为三角形的三边长,计算三角形的面积。注意在程序里检查输入数据,对不能构成三角形的情况给出错误信息。仔细
分析自己的程序,能否检查出所有不合理数据。用不同数据运行试验。
19. 写一个程序,它读入一系列整数,最后输出其中最大的两个数。
//——读入一系列数,最后输出其中最大的两个
#include
int main(){
long x,max1=-1000000,max2=-100000;
while(scanf("%d",&x)==1){
if(x!=max1&&x>max2)
{if(x>max1)
{max2=max1;
max1=x;}
else
max2=x;
}
}
printf("max1=%d max2=%d\n",max1,max2);
system("pause");
return 0;
20. 写一个程序,它输出所读入的一系列整数的平均值。假定给它的第一个数并不是数据,而是用于说明数据的项数。
21. 假设程序由输入得到的一系列正实数是一条折线在x等于0,1,2,„的对应值(数据的数目事先并未确定),请求出这一折线与x轴之间区域的面积。
答:
—求折线与x轴之间区域的面积。可以看成是几个梯形面积和
#include
int main(){
int y,count=0;
double s=0.0;
while(scanf("%d",&y)==1){
if(count==0)s+=y/2.; //s加第一个输入值的1/2,即s=1/2*X1
else s+=y; //s开始累加输入的值,此处包括最后一个数,即Xn;
++count;
}
s=s-y/2.; //由于刚才多加了最后输入的数的1/2,也就是1/2的Xn,所以要减去。
printf("s=%fm^2\n",s);
system("pause");
return 0;
}
22. 能够组成直角三角形三个边的最小一组整数是3、4、5。写程序求出在一定范围里所有可以组成直角三角形三个边的整数组,输出三个一组的整数。设法避免重复的组。
23. 改造本章正文中讨论的计算器程序:
1)增加计算一行后的处理,使出现在正确表达式之后的任意字符序列都不会影响下一表达式的计算(抛弃正确表达式之后的字符)。
2)修改程序,使之在数值、加号之间出现任意个空格时都能正确计算。
3)修改程序,使之不仅能处理加法,还能处理其他算术运算符(提示:记录运算符,用if或者switch判断、计算和输出)。
24. 仿照本章正文中的单词统计程序,写一个统计C程序里标识符个数的程序。在程序里可以利用标准库提供的字符分类函数:
int isalpha(int c) 当c是字母的编码时,返回非0
值;
int isdigit(int c) 当c是数字的编码时,返回非0
值。
使用这两个函数时,应在程序文件前部写 #include 。
25. 定义下面的计算规则:遇到1就终止;如果遇到1之外的奇数,求出它乘3加1的值作为下一个数;如果遇到偶数,求出它除以2的值作为下一个数。问题是:对每个正整数,反复使用这套规则,最终是否都能得到1。也就是问,按照这个规则定义的递推序列是否对每个正整数都终止(这个著名问题至今也没有结论)。请按上面的规则定义一个函数,它返回对参数计算直到终止所经历的计算步数。对一系列参数试验这个函数。注意:序列中的数可能变得很大,请设法检查溢出,遇到溢出时打印信息。
26. 考察目前银行对各种期限的储蓄利率。写一个函数,它能够计算出对给定的时间(例如8年,10.5年等,以半年为基本单位)如何分段将能够得到最大的收益。
27. 为本章正文中的某些程序实例写出好用的测试驱动程序。为你所做的某些练习写出好用的测试驱动程序,并
