1、各章练习题答案第1章 C语言概述1.1 简答题1 答:C语言单词分为保存字、标记符、字面常量、运算符和分隔符5类。2 答:首字符必须是英文字母或下划线;其余位置上的字符必须是英文字母、十进制数字符号或下划线。3 答:它们的首字符不同,此外各自尚有具体的格式规定。其中,数值字面常量以数字、正负号或小数点(如.01表达0.01)开头,字符字面常量必须用单引号括起来,字符串字面常量必须用双引号括起来,标记符首字符必须是英文字母或下划线。4 答:分类如下。数值常量3个:25 -8 +3.42字符常量3个:4 D +字符串7个:x1 -28 y=m+1 a12.c else + int x;标记符7个:
2、x2 n count main Hlist xy MaxA_1保存字3个:int void if运算符1个:+分隔符0个:非法数据1个:3ab以上共计25个。5 答:C语句除空语句外,按照语句功能,可分为以下8类:类型定义语句、变量定义语句、函数原型语句、表达式语句、复合语句、选择语句、循环语句和跳转语句。在以上8类语句中,前3类属于说明性语句,后5类属于执行性语句。6 答:其格式为:#include 或#include “头文献。对于每条预解决包含命令,在预解决阶段将把该命令置换为所指定“头文献”中的所有内容,换句话说,是用该“头文献”保存的所有内容代替该预解决包含命令行。 对于上述给出的两
3、种包含命令格式,系统解决时的查找头文献的途径有所不同。对于第一种格式(即尖括号格式),将从C语言系统层次目录中查找头文献,若查找不到则给犯错误信息;对于第二种格式(即双引号格式),假如头文献名没有给出磁盘号和途径名,则一方面从当前工作目录(即包含该命令的程序文献所属的目录)中查找头文献,若查找不到,再接着从C语言系统层次目录中查找头文献,若还是查找不到则给犯错误信息。在第二种格式中,假如头文献名带有磁盘号和途径名,则只在该指定途径中查找头文献,若查找不到则给犯错误信息。(关于第二种格式中头文献名带有磁盘号和途径名的情况,教材的叙述是错误的)7 答:第一步需要上机建立相应的工作区和项目并建立、输
4、入和编辑该程序中的相应文献,通常一方面建立主文献;第二步对每个程序文献进行编译生成各自的目的代码文献,通常主文献被一方面编译并生成目的文献;第三步使主目的文献与同一程序中的其他目的代码文献以及有关C语言系统库函数文献相连接,生成一个可执行文献;第四步运营最后生成的可执行文献。1.2 选择题1B2C3A4D5A6B7D8C上机实验题1 程序代码:#include void main() int x, y;x = 5; y = 6;printf(x + y = %d, , x + y);printf(x * y = %dn, x * y);运营结果:x + y = 11, x * y = 302
5、程序代码:#include int cube(int);void main() printf(cube(3) = %dn, cube(3);printf(cube(5) = %dn, cube(5);printf(cube(8) = %dn, cube(8);int cube(int x) return x * x * x; 运营结果:cube(3) = 27cube(5) = 125cube(8) = 5123 程序代码:A主程序文献代码:#include #include abc.cppvoid main() double a, b, c;double averageValue;a = 2
6、; b = 3; c = 4;averageValue = AVE(a, b, c);printf(averageValue: %lfn, averageValue);averageValue = AVE(a + 1, b + 2, c + 5);printf(averageValue: %Lfn, averageValue);Babc.cpp文献代码:(新建时选择“File|New|C+ Source File”。注意去掉“Add to project:”前面的勾,以后新建其他程序文献或头文献时还要勾上)double AVE(double x, double y, double z)retu
7、rn (x + y + z) / 3;运营结果:averageValue: 3.000000averageValue: 5.6666674 程序代码:A主程序文献代码:#include #include example.hvoid main() int a, b, c;printf(请输入任意三个整数:);scanf(%d %d %d, &a, &b, &c);printf(求和:%dn, Sum(a, b, c);printf(乘积:%dn, Product(a, b, c);Bexample.h头文献代码:(新建时选择“File|New|C/C+ Header File”。注意勾上“Add
8、 to project:”前面的勾)int Sum(int, int, int);int Product(int, int, int);C另一个程序文献的代码:(新建时选择“File|New|C+ Source File”。注意勾上“Add to project:”前面的勾)int Sum(int a, int b, int c)return a + b + c;int Product(int a, int b, int c)return a * b * c;运营结果随输入不同而不同,请自行记录第2章 基本数据类型与表达式2.1选择题1D2A3B4B5D6C7C8A9C10D11B12C13A
9、2.2把下列数学算式或不等式表达成C表达式12.0 * x * (1 + x * x / 3.0)2(1 + exp(x) / (1 - exp(x)3(-b + sqrt(b * b - 4.0 * a * c) / 2 / a41 / (3.0 * x * log(2.0 * x + k)5pow(sin(x + 3.14159 / 4), 3) / (3 + pow(cos(x - 3.14159 / 4), 3)6pow(1 + exp(x + 1), n) / 770 = x & x = 208(a * x - b * y) != c9(4 * x + 7 * y - 2) = 3
10、* a * b10(3.0 * x + 2) != 0 & fabs(2.0 * x * x + 1) / (3.0 * x + 2) = 55 | pay = 82012! strcmp(place, 江苏) & ! strcmp(sex, 女)/* strcmp函数详见教材第127页*/13(a = ch & ch = z) | (A = ch & ch = Z)14s2 = 0 & (s1 = x | s1 = X)/*s1、s2为数组元素,详见第4章*/2.3求出下列逻辑表达式的相反式1!x2x != 03x 104p = NULL | x = 465x = 106ch != d &
11、ch != D7! p | p-data = x/*p-data是对结构成员的间接访问,详见教材第193页7.3*/8i = n & ai % 3 != 0/*ai为数组元素,详见第4章*/2.4根据下列题目规定编写出相应程序1(题目中仅规定两边之和大于等于第三边是不对的。两边之和等于第三边只能连成直线(根据公式计算面积也为0),不能组成三角形。边长也不应为负数。故应规定两边之和大于第三边,且任一边长大于0。但是目前没有学习第3章的if语句,程序自身无法控制在碰到不能构成三角形的情况时如何解决,需要用户输入时自行掌握。)#include #include void main() double
12、a, b, c, s;printf(请输入三角形三条边长:);scanf(%lf %lf %lf, &a, &b, &c);s = (a + b + c) / 2;printf(该三角形面积为:%lfn, sqrt(s * (s - a) * (s - b) * (s - c);2(每年都是上一年的110%,即1.1倍,5年后则将是1.1的5次方。其实只有5次方,为什么一定要用pow(1.1, 5)呢_?1.1 * 1.1 * 1.1 * 1.1 * 1.1效率多高!但是要注意人数是没有零头的,所以要ceil()一下。之所以用ceil()而不是floor()是为了保证完毕任务,一个都不能少,呵
13、呵。本题这样算出来的是4832人。但是更严格的做法就是要每年都ceil()一下,否则中间某个年份招生人数就有零头了,本题这样算出来的是4836人。只是那样的话就成了:ceil(ceil(ceil(ceil(ceil(3000 * 1.1) * 1.1) * 1.1) * 1.1) * 1.1) 晕吧,哈哈。要想不晕,得学好第3章的循环语句。)#include #include void main() printf(5年后计划招生%lf人。n, ceil(3000 * pow(1.1, 5);3(算术平均值:求和之后除以n,几何平均值:乘积的n次方根(即1.0/n次方)。为了防止数值过大溢出(超
14、过整数类型的范围),所以对第一个数就使用了强制类型转换为double。此外本题计算乘积的4次方根,规定输入的四个整数假如全都不为0,则应有0、2或4个为正,否则乘积为负,无实数4次方根。)#include #include void main() int a, b, c, d;printf(请输入4个整数:);scanf(%d %d %d %d, &a, &b, &c, &d);printf(算术平均值:%lf,几何平均值:%lf。n,(double)a + b + c + d) / 4,pow(double)a * b * c * d, 1.0 / 4);4(唯一规定:a和b不能是相反数,即
15、a不等于-b。拜托,拜托!)#include #include void main() double a, b;printf(请输入a和b的值:);scanf(%lf %lf, &a, &b);printf(x = %lf, y = %lfn,2 * a * sin(a) / 3 / (a + b),2 * b * cos(b) / 3 / (a + b);上机实验题1#include #include #include const int N = 10;void main() int i, x, y, z, c = 0;srand(time(0);for(i = 1; i = N; i +)
16、 x = rand() % 90 + 10; / 0+10, 89 + 10y = rand() % 90 + 10; / 0+10, 89 + 10printf(%d + %d = , x, y);scanf(%d, &z);if(x + y = z) c +; / 本题回答对的printf(最后得分:%dn, c * 10);2(与教材不同,使用了t。这是制表符,相称于按Tab键排版。由于使用了t,所以%10.2lf也省略为%.2lf,即不限定宽度,只限定小数位数为2位。注意教材上第一个printf语句中,cos误为con了。请尝试将while改为for、dowhile。)#include
17、 #include const double RAD = 3.14159 / 180;void main() int i = 0;printf(titsintcosn);while(i = 90) printf(t%dt%.2lft%.2lfn, i, sin(i * RAD), cos(i * RAD);i += 5;3(正整数范围大约21亿多,故输入的数以9位或以下(小于10亿)为宜,牢记牢记!)#include void main() int num, rem;printf(输入一个整数:);scanf(%d, &num);do rem = num % 10; / 得到个位的值/* 去掉
18、个位,这样下次的个位就是现在的十位。每次如此,即可逐次得到从个位到最高位的各位 */num /= 10;/ 输出现在的个位。由于从个位开始逐位输出,所以顺序反过来了printf(%d, rem);/* 循环必须用dowhile,这样当num为0时也会循环一次,输出一个0。开始不为0时,当去掉最高位后num自然也就是0了,结束循环 */ while(num 0);printf(n);4(呵呵,for语句与教材的不同。其中表达式1可以省略,这不奇怪;每次循环ch+和d1+都执行一次,所以表达式2只需要判断ch = F,这也不奇怪。两条printf合成一句,大多数同学也会。但是ch +和d1 +怎么
19、和printf合并成表达式3?因素在于由于是后缀+,所以给printf()的值事实上都是d1和ch,值给了printf()之后才增长1,所以+事实上仍然是在printf()输出之后做的。)#include void main() char ch = A, d1 = a;for(;ch = F;printf(%c : %d, %c : %dn, ch +, ch, d1 +, d1);5(比教材多了一点换行,程序排版好看点。注意有整数除法,所以y不能为0,并且输入除法答案的时候要舍去小数部分啊!)#include void main() int x, y, z, c = 0;printf(输入两
20、个整数:);scanf(%d %d, &x, &y);printf(%d + %d = , x, y); scanf(%d, &z); if(x + y = z) c+;printf(%d - %d = , x, y); scanf(%d, &z); if(x - y = z) c+;printf(%d * %d = , x, y); scanf(%d, &z); if(x * y = z) c+;printf(%d / %d = , x, y); scanf(%d, &z); if(x / y = z) c+;printf(%d % %d = , x, y); scanf(%d, &z);
21、if(x % y = z) c+;printf(n共5道题,答对%d道题n, c);第3章 流程控制语句3.1选择题1A2B3C4D5*C6B7C8B9A10D(问题一:第5小题。一般而言,循环体每次执行完之后都会执行,然后再计算,判断是否中止循环,即使在循环体中碰到continue也不会跳过的执行。但是,假如在循环体中执行break则会立即终止循环,也就是说会被跳过,在这种情况下,循环体就被多执行了一次。)3.2写出下列程序运营结果并上机验证1(第一个if改用条件表达式,注意最后一个printf之前的一行,每执行一个赋值语句,相关变量的值就被改变了,变量的新值参与下一个赋值语句中的运算,所以
22、执行了a += b; b += a;之后,b和a的值不等。)#include void main() int a = 2, b = 5, c;c = (a + b 10)? (a * b) : (3 * a + 2 * b);if(c = 20) printf(%d, c * c);else if(a b) printf(%d, 3 * (a + b);else printf(%d, 4 * c - 5);printf(n);a += b; b += a; c += a + b;printf(a=%d, b=%d, c=%dn, a, b, c);2(注意三处:x += 2、switch(x
23、- 1)、除了case 10之后有break,别的没有break。)#include void main() int x;for(x = 5; x 12; x += 2) / x: 5 7 9 11switch(x - 1) case 4: printf(%dn, x); / x: 5case 7: printf(%dn, 2 * x + 1); / x: 5case 10: printf(%dn, 3 * x - 1); break; / x: 5 11default: printf(defaultn); / x: 7 93(规定输入的数在第96页)#include void main()
24、int s0, s1, s2, x;s0 = s1 = s2 = 0;printf(从键盘输入一组整数(以-1结束):n);scanf(%d, &x);while(x != -1) / -1结束switch(x % 3) case 0: s0 += x; break; / 能被3整除的数之和case 1: s1 += x; break; / 除以3余1的数之和case 2: s2 += x; break; / 除以3余2的数之和scanf(%d, &x);printf(s0=%d, s1=%d, s2=%dn, s0, s1, s2);4(学会数数,呵呵。)#include void main
25、() int c1 = 0, c2 = 0, c3 = 0;int i, j, k;for(i = 0; i 5; i +) for(j = i; j = i; k -) c2 +; / 循环6 + 5 + 4 + 3 + 2 = 20次c3 +; / 5次printf(%d %d %dn, c1, c2, c3);5#include const int B = 2;void main() int i = 0, p = 1, s = 1;while(s =100循环才结束i +; p *= B; s += p;/ 循环次数ips/ 1123/ 2247/ 33815/ 441631/ 5532
26、63/ 6664127printf(i = %dn, i);printf(s = %dn, s);6(对正整数1016分解质因数。)#include void main() int i;for(i = 10; i = 16; i +) int j = 2, k = i; / j从最小的质数2开始printf(%d: , i);do /* 在下面的循环中,假如k能被j整除,则j必为k的质因数。由于j是从最小的质数2开始逐个增长的,只要可以整除k的j都会完全被while循环分解(k/=j),所以当j增长到合数j时,j的各个质因数(均小于j)都已经被分解完毕,故而此时的k已经不能被j整除了。j必为k
27、的质因数。合数就是可以被1和自身之外的数整除的数,即:j=p1*p2*p3*pn,其中pi为质数,且pi1。*/while(k % j = 0) printf(%d , j); k /= j; j +; while(k = j);printf(n);7(不要光靠数数啊,呵呵。)#include const int T=6;void main() int i, j, k = 0;for(i = 1; i = T; i += 2) / i: 1 3 5for(j = 2; j = T; j +) / j: 2 3 4 5 6if(i + j = T) printf(+); / (i, j): (1
28、, 5) (3, 3)else if(i * j = T) printf(*); / (i, j): (1, 6) (3, 2)else k +; / 共循环3*5=15次,上面两种情况4次,这里11次printf(nk=%dn, k);8(对照第6小题。这里的while循环和第6小题的while很像吧?不错,这里的i和第6小题的j类似,是用来寻找质因数的。只是由于while的条件表达式不同,寻找的是x和y两者的公共质因数i。p将所有的公共质因数i乘起来,得到的是两者的最大公约数。最小公倍数本应当是两数乘积除以最大公约数,但是由于在while循环中x和y已经各自除以所有的公共质因数,也就是说x
29、和y各自都已经除以一次最大公约数了,总共除了两次,所以最后反而要乘回来一次。因此printf中的附加参数是p * x * y。)#include void main() int x, y;int i = 2, p = 1;printf(请输入两个正整数x和y:);scanf(%d %d, &x, &y);do while(x % i = 0 & y % i = 0) p *= i;x /= i;y /= i;i +; while(x = i & y = i);printf(x和y的最小公倍数为%dn, p * x * y);3.3指出下列程序功能并上机验证1(程序功能:计算数学公式,其中n从键
30、盘输入,规定n=2。本程序用到了函数定义的知识。)#include double f1(int n) / 函数f1:规定一个整型参数,计算结果(返回值)为实数int i;double sign = 1, s = 1;for(i = 2; i = n; i +) / 从2开始累加至ns += sign / (i * i); / sign含义见下。s每次加上 (-1)i/i2sign *= - 1; / sign每次都乘以-1,初值为1=(-1)2,故sign=(-1)ireturn s; / 返回计算结果svoid main() int a;printf(输入一个大于等于2的整数:);do sc
31、anf(%d, &a); while(a = 1); / 输入的数a不大于等于2则要重新输入printf(%lfn, f1(a); / 调用f1(a)计算,并将计算结果输出2(与第2章上机实验题第3小题功能相同,请参照阅读。注意48是0的ASCII码,由于09在ASCII码表中连续排列,所以数字09加上48就成为相应的数字字符。)#include void main() int x;printf(输入一个整数:);scanf(%d, &x);while(x) int k = x % 10;printf(%c, k + 48);x = x / 10;printf(n);3(答案很简朴!看到最后两
32、行printf就行了,呵呵。考试考这题多好啊!函数f2求两数的最小公倍数,与本章练习题3.2的第8小题的算法同样。函数f1求两数的最大公约数,虽然f2中求最小公倍数的同时也得到了最大公约数p,但f1的效率高得多。f1采用的算法称为辗转相除法,又称欧几里得算法,具体描述见教材第82页对程序3-12的说明。辗转相除法的证明:设a整除以b的余数为 r,即a=q*b+r,其中q为整数。将a和b的最大公约数写作gcd(a, b),b和r的最大公约数则为gcd(b, r)。由于r =a-q*b,而a、b均能被gcd(a, b)整除,所以r显然也能被gcd(a, b)整除。既然b和r都能被gcd(a, b)
33、整除,则gcd(a, b)是b和r的公约数,所以gcd(a, b)不也许大于b和r的最大公约数gcd(b, r)。反过来,由于b和r均能被gcd(b, r)整除,而a=q*b+r,所以a也能被gcd(b, r)整除。既然a和b都能被gcd(b, r)整除,则gcd(b, r)是a和b的公约数,从而不也许大于a和b的最大公约数gcd(a, b)。绕了半天,我们得到gcd(a, b)=gcd(b, r)并且gcd(b, r)=gcd(a, b),那么就只能有:gcd(a, b)=gcd(b, r)。即,a和b的最大公约数必然也是它们的余数和它们的最大公约数。这样,可以进行辗转相除,迅速将参与运算的
34、两个数变小,不久得到结果。)#include int f1(int a, int b) int r;while(b != 0) r = a % b;a = b; b = r;/ 此时有b = 0。由于循环结束前进行了a=b; b=r;的赋值,所以实际是最后一次求得的/ 余数r = 0,也就是最后一次循环时(执行a=b; b=r;前)有a=n*b,其中n为整数。/ 这时的a和b的最大公约数自然是b,也就是执行了a=b;后的a是最大公约数。return a;int f2(int a, int b) int i = 2, p = 1;do while(a % i = 0 & b % i = 0) p
35、 *= i; a /= i; b /= i;i +; while(a = i & b = i);return p * a * b;void main() int a, b;printf(输入两个正整数:);do scanf(%d %d, &a, &b); while(a = 0 | b = 0);printf(%d和%d的最大公约数:%dn, a, b, f1(a, b);printf(%d和%d的最小公倍数:%dn, a, b, f2(a, b);4(教材错误:ff函数中的scanf语句应在switch语句之前。程序功能:出10道20以内整数加减乘除运算题,记录用户得分。每做对一题得10分。
36、)#include #include #include const int N = 10;int ff(int x, int y, char op);void main() int i, a, b, c = 0, d;char op;srand(time(0);for(i = 0; i N; i +) a = rand() % 20 + 1;b = rand() % 20 + 1;d = rand() % 4;if(d = 0) op = +;else if(d = 1) op = -;else if(d = 2) op = *;else op = /;if(ff(a, b, op) c +;
37、printf(得分:%dn, c * 10);int ff(int x, int y, char op) int z;printf(%d %c %d = , x, op, y);scanf(%d, &z);/ 判断对op指定的运算,用户给出的答案是否对的。返回判断结果(逻辑值)switch(op) case +: return x + y = z; / 都return了,就不用break了case -: return x - y = z; case *: return x * y = z;case /: return x / y = z;/ 尽管本程序可以不要default,但ff也许用于别处
38、,op也许会被指定错误的值/ 检查非法参数取值,这是好习惯。但是简朴地exit在大程序中是不好的解决default: printf(运算符错!n); exit(1); 3.4根据下列题目规定编写程序并上机得到运营结果1(不要用pow函数啊,同志!整数的整数次方,还是这个好。假如只求一两个高次幂,则有更高效的办法而不要象下面那样逐次乘上去。此外高次幂要小心溢出整数范围。后记:糗事一件,居然开始的时候习惯性地把p *= 3写成p *= i了,最终结果就成了1。哈哈,我还纳闷,这个程序怎么会错呢?)#include void main() int i, p = 1, sum = 0;for(i =
39、0; i = 10; i +) sum += p;p *= 3;printf(%dn, sum);2(见注释。)#include void main() int i, sum;for(i = 0, sum = 0; sum 1000; ) i += 2;sum += i * i;/ 循环结束时,sum已经大于等于1000,即多加了一项/ 所以最大的n应是前一项,即i - 2printf(%dn, i - 2);3(注意printf里x = 0为假时的求值表达式。对于多项式计算,反复用高项系数乘以自变量加低项系数,可以极大地减少乘法次数。即,对于多项式,可以写成:(.(an * x + an-1
40、) * x + an-2) * x . + a2) * x + a1) * x + a0假如按本来的多项式计算,不作任何优化,则需要n + (n - 1) + . + 2 + 1 = (n + 1)n/2次乘法;而改造后只需要n次乘法。当n较大时两者的差异是明显的。)#include #include const double a = 1.0;void main() double x;printf(请输入一个实数x:);scanf(%lf, &x);printf(y = %lfn,(x = 0)?sqrt(a * a + x * x): ( (3 * a * a * x + 4) * a * x - 1 );4(一般教材当然认为这种题目应当用双重循环,对a、b的所有也许取值情况所有判断一下不定方程是否成立。对于复杂一点的方程也许不得不如此,但是这儿用那种办法显然笨死了!对每个a的取值,计算相应的b,然后看b是否符合条件这不就够了吗?记住由于求b用了整数除法,所以得到的b只是真正的解的整数部分。所以在判断b是否在1536之间的同时还要检查b是不是真的是原方程