1、各章练习题答案 第1章 C语言概述 1.1 简答题 1. 答:C语言单词分为保存字、标记符、字面常量、运算符和分隔符5类。 2. 答:首字符必须是英文字母或下划线;其余位置上的字符必须是英文字母、十进制数字符号或下划线。 3. 答:它们的首字符不同,此外各自尚有具体的格式规定。其中,数值字面常量以数字、正负号或小数点(如.01表达0.01)开头,字符字面常量必须用单引号括起来,字符串字面常量必须用双引号括起来,标记符首字符必须是英文字母或下划线。 4. 答:分类如下。 数值常量3个:25 -8 +3.42 字符常量3个:'4' 'D' '+' 字符串7个:"x1" "-2
2、8" "y=m+1" "a12.c" "else" "+" "int x;" 标记符7个: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语言系统层次目录中查找头文献,若还是查找不到则给犯错误信息。在第二种格式中,假如头文献名带有磁盘号和途径名,则只在该指定途径中查找头文献,若查找
4、不到则给犯错误信息。(关于第二种格式中头文献名带有磁盘号和途径名的情况,教材的叙述是错误的)
7. 答:第一步需要上机建立相应的工作区和项目并建立、输入和编辑该程序中的相应文献,通常一方面建立主文献;第二步对每个程序文献进行编译生成各自的目的代码文献,通常主文献被一方面编译并生成目的文献;第三步使主目的文献与同一程序中的其他目的代码文献以及有关C语言系统库函数文献相连接,生成一个可执行文献;第四步运营最后生成的可执行文献。
1.2 选择题
1.B 2.C 3.A 4.D 5.A 6.B 7.D 8.C
上机实验题
1. 程序代码:
#include
5、oid main() {
int x, y;
x = 5; y = 6;
printf("x + y = %d, ", x + y);
printf("x * y = %d\n", x * y);
}
运营结果:
x + y = 11, x * y = 30
2. 程序代码:
#include
6、\n", cube(8));
}
int cube(int x) { return x * x * x; }
运营结果:
cube(3) = 27
cube(5) = 125
cube(8) = 512
3. 程序代码:
A.主程序文献代码:
#include
7、alue: %lf\n", averageValue); averageValue = AVE(a + 1, b + 2, c + 5); printf("averageValue: %Lf\n", averageValue); } B.abc.cpp文献代码:(新建时选择“File|New|C++ Source File”。注意去掉“Add to project…:”前面的勾,以后新建其他程序文献或头文献时还要勾上) double AVE(double x, double y, double z) { return (x + y + z) / 3; } 运营结果:
8、averageValue: 3.000000
averageValue: 5.666667
4. 程序代码:
A.主程序文献代码:
#include
9、择“File|New|C/C++ Header File”。注意勾上“Add 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;
10、 } 运营结果随输入不同而不同,请自行记录 第2章 基本数据类型与表达式 2.1选择题 1.D 2.A 3.B 4.B 5.D 6.C 7.C 8.A 9.C 10.D 11.B 12.C 13.A 2.2把下列数学算式或不等式表达成C表达式 1.2.0 * x * (1 + x * x / 3.0) 2.(1 + exp(x)) / (1 - exp(x)) 3.(-b + sqrt(b * b - 4.0 * a * c)) / 2 / a 4.1 / (3.0 * x * log(2.0 * x + k)) 5.pow(sin(x + 3.14159 /
11、 4), 3) / (3 + pow(cos(x - 3.14159 / 4), 3)) 6.pow(1 + exp(x + 1), n) / 7 7.0 <= x && x <= 20 8.(a * x - b * y) != c 9.(4 * x + 7 * y - 2) == 3 * a * b 10.(3.0 * x + 2) != 0 && fabs((2.0 * x * x + 1) / (3.0 * x + 2)) <= 5 /*(3.0 * x + 2)先判断避免去0*/ 11.age >= 55 || pay >= 820 12.! strcmp(place,
12、"江苏") && ! strcmp(sex, "女")/* strcmp函数详见教材第127页*/ 13.('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') 14.s[2] == '0' && (s[1] == 'x' || s[1] == 'X')/*s[1]、s[2]为数组元素,详见第4章*/ 2.3求出下列逻辑表达式的相反式 1.!x 2.x != 0 3.x < 10 4.p == NULL || x == 46 5.x <= 0 || x >= 10 6.ch != 'd' && ch != 'D' 7.!
13、 p || p->data == x/*p->data是对结构成员的间接访问,详见教材第193页7.3*/
8.i >= n && a[i] % 3 != 0/*a[i]为数组元素,详见第4章*/
2.4根据下列题目规定编写出相应程序
1.(题目中仅规定两边之和大于等于第三边是不对的。两边之和等于第三边只能连成直线(根据公式计算面积也为0),不能组成三角形。边长也不应为负数。故应规定两边之和大于第三边,且任一边长大于0。但是目前没有学习第3章的if语句,程序自身无法控制在碰到不能构成三角形的情况时如何解决,需要用户输入时自行掌握。)
#include
14、lude
15、效率多高!但是要注意人数是没有零头的,所以要ceil()一下。之所以用ceil()而不是floor()是为了保证完毕任务,一个都不能少,呵呵。本题这样算出来的是4832人。但是更严格的做法就是要每年都ceil()一下,否则中间某个年份招生人数就有零头了,本题这样算出来的是4836人。只是那样的话就成了:
ceil(ceil(ceil(ceil(ceil(3000 * 1.1) * 1.1) * 1.1) * 1.1) * 1.1)
晕吧,哈哈。要想不晕,得学好第3章的循环语句。)
#include
16、 {
printf("5年后计划招生%lf人。\n", ceil(3000 * pow(1.1, 5)));
}
3.(算术平均值:求和之后除以n,几何平均值:乘积的n次方根(即1.0/n次方)。为了防止数值过大溢出(超过整数类型的范围),所以对第一个数就使用了强制类型转换为double。此外本题计算乘积的4次方根,规定输入的四个整数假如全都不为0,则应有0、2或4个为正,否则乘积为负,无实数4次方根。)
#include
17、");
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不能是相反数,即a不等于-b。拜托,拜托!)
#include
18、f", &a, &b);
printf("x = %lf, y = %lf\n",
2 * a * sin(a) / 3 / (a + b),
2 * b * cos(b) / 3 / (a + b));
}
上机实验题
1.
#include
19、rand() % 90 + 10; // [0+10, 89 + 10] y = rand() % 90 + 10; // [0+10, 89 + 10] printf("%d + %d = ", x, y); scanf("%d", &z); if(x + y == z) c ++; // 本题回答对的 } printf("最后得分:%d\n", c * 10); } 2.(与教材不同,使用了'\t'。这是制表符,相称于按Tab键排版。由于使用了'\t',所以%10.2lf也省略为%.2lf,即不限定宽度,只限定小数位数为2位。注意教材上第一个prin
20、tf语句中,"cos"误为"con"了。请尝试将while改为for、do~while。)
#include
21、入的数以9位或以下(小于10亿)为宜,牢记牢记!)
#include
22、~while,这样当num为0时也会循环一次,输出一个0。 开始不为0时,当去掉最高位后num自然也就是0了,结束循环 */ } while(num > 0); printf("\n"); } 4.(呵呵,for语句与教材的不同。其中表达式1可以省略,这不奇怪;每次循环ch++和d1++都执行一次,所以表达式2只需要判断ch <= 'F',这也不奇怪。两条printf合成一句,大多数同学也会。但是ch ++和d1 ++怎么和printf合并成表达式3?因素在于由于是后缀++,所以给printf()的值事实上都是d1和ch,值给了printf()之后才增长1,所以++
23、事实上仍然是在printf()输出之后做的。)
#include
24、整数:"); 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+
25、 printf("%d %% %d = ", x, y); scanf("%d", &z); if(x % y == z) c++; printf("\n共5道题,答对%d道题\n", c); } 第3章 流程控制语句 3.1选择题 1.A 2.B 3.C 4.D 5*.C 6.B 7.C 8.B 9.A 10.D (问题一:第5小题。一般而言,循环体每次执行完之后都会执行<表达式3>,然后再计算<表达式2>,判断是否中止循环,即使在循环体中碰到continue也不会跳过<表达式3>的执行。但是,假如在循环体中执行break则会立即终止循环,也就是说<表达式3
26、>会被跳过,在这种情况下,循环体就被多执行了一次。)
3.2写出下列程序运营结果并上机验证
1.(第一个if改用条件表达式,注意最后一个printf之前的一行,每执行一个赋值语句,相关变量的值就被改变了,变量的新值参与下一个赋值语句中的运算,所以执行了a += b; b += a;之后,b和a的值不等。)
#include
27、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=%d\n", a, b, c);
}
2.(注意三处:x += 2、switch(x - 1)、除了case 10之后有break,别的没有break。)
#include
28、 // x: 5 7 9 11
switch(x - 1) {
case 4: printf("%d\n", x); // x: 5
case 7: printf("%d\n", 2 * x + 1); // x: 5
case 10: printf("%d\n", 3 * x - 1); break; // x: 5 11
default: printf("default\n"); // x: 7 9
}
}
}
3.(规定输入的数在第96页)
#include
29、2, 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=
30、d\n", s0, s1, s2);
}
4.(学会数数,呵呵。)
#include
31、tf("%d %d %d\n", c1, c2, c3);
}
5.
#include
32、4 127
}
printf("i = %d\n", i);
printf("s = %d\n", s);
}
6.(对正整数10~16分解质因数。)
#include
33、le循环分解(k/=j),所以当j增长到合数j'时,j'的各个质因数(均
小于j')都已经被分解完毕,故而此时的k已经不能被j'整除了。j必为k
的质因数。
合数就是可以被1和自身之外的数整除的数,即:
j'=p1*p2*p3*…*pn,其中pi为质数,且pi 34、io.h>
const int T=6;
void main() {
int i, j, k = 0;
for(i = 1; i <= T; i += 2) // i: 1 3 5
for(j = 2; j <= T; j ++) // j: 2 3 4 5 6
if(i + j == T) printf("+"); // (i, j): (1, 5) (3, 3)
else if(i * j == T) printf("*"); // (i, j): (1, 6) (3, 2)
else k ++; // 共循环3*5=15次,上面两种情况4次,这里 35、11次
printf("\nk=%d\n", k);
}
8.(对照第6小题。这里的while循环和第6小题的while很像吧?不错,这里的i和第6小题的j类似,是用来寻找质因数的。只是由于while的条件表达式不同,寻找的是x和y两者的公共质因数i。p将所有的公共质因数i乘起来,得到的是两者的最大公约数。最小公倍数本应当是两数乘积除以最大公约数,但是由于在while循环中x和y已经各自除以所有的公共质因数,也就是说x和y各自都已经除以一次最大公约数了,总共除了两次,所以最后反而要乘回来一次。因此printf中的附加参数是p * x * y。)
#include 36、>
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的最小公倍数为%d\n", p * x * y);
}
3.3指出下列程序功能并上机验证
1.(程序功能:计算数学公 37、式,其中n从键盘输入,规定n>=2。本程序用到了函数定义的知识。)
#include 38、 // 返回计算结果s
}
void main() {
int a;
printf("输入一个大于等于2的整数:");
do scanf("%d", &a); while(a <= 1); // 输入的数a不大于等于2则要重新输入
printf("%lf\n", f1(a)); // 调用f1(a)计算,并将计算结果输出
}
2.(与第2章上机实验题第3小题功能相同,请参照阅读。注意48是'0'的ASCII码,由于'0'~'9'在ASCII码表中连续排列,所以数字0~9加上48就成为相应的数字字符。)
#include 39、 {
int x;
printf("输入一个整数:");
scanf("%d", &x);
while(x) {
int k = x % 10;
printf("%c", k + 48);
x = x / 10;
}
printf("\n");
}
3.(答案很简朴!看到最后两行printf就行了,呵呵。考试考这题多好啊!函数f2求两数的最小公倍数,与本章练习题3.2的第8小题的算法同样。函数f1求两数的最大公约数,虽然f2中求最小公倍数的同时也得到了最大公约数p,但f1的效率高得多。f1采用的算法称为辗转相除法,又称欧几里得算法,具体描述见教 40、材第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)整除,则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)整除,则g 41、cd(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的最大公约数必然也是它们的余数和它们的最大公约数。这样,可以进行辗转相除,迅速将参与运算的两个数变小,不久得到结果。)
#include 42、 // 此时有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 *= i; a /= i; b /= i;
}
i ++;
} while(a 43、 >= 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的最大公约数:%d\n", a, b, f1(a, b));
printf("%d和%d的最小公倍数:%d\n", a, b, f2(a, b));
}
4.(教材错误:ff函数中的scanf语句应在switch语句之前。
程序功能:出10道20以内整数加减乘除运算题 44、记录用户得分。每做对一题得10分。)
#include 45、d == 0) op = '+';
else if(d == 1) op = '-';
else if(d == 2) op = '*';
else op = '/';
if(ff(a, b, op)) c ++;
}
printf("得分:%d\n", c * 10);
}
int ff(int x, int y, char op) {
int z;
printf("%d %c %d = ", x, op, y);
scanf("%d", &z);
// 判断对op指定的运算,用户给出的答案是否对的。返回判断结果(逻辑值)
sw 46、itch(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也许用于别处,op也许会被指定错误的值
// 检查非法参数取值,这是好习惯。但是简朴地exit在大程序中是不好的解决
default: { printf("运算符错!\n"); exit(1); }
}
}
3 47、4根据下列题目规定编写程序并上机得到运营结果
1.(不要用pow函数啊,同志!整数的整数次方,还是这个好。假如只求一两个高次幂,则有更高效的办法而不要象下面那样逐次乘上去。此外高次幂要小心溢出整数范围。
后记:糗事一件,居然开始的时候习惯性地把p *= 3写成p *= i了,最终结果就成了1。哈哈,我还纳闷,这个程序怎么会错呢?)
#include 48、\n", sum);
}
2.(见注释。)
#include 49、于多项式,可以写成:
((...((an * x + an-1) * x + an-2) * x ... + a2) * x + a1) * x + a0
假如按本来的多项式计算,不作任何优化,则需要n + (n - 1) + ... + 2 + 1 = (n + 1)n/2次乘法;而改造后只需要n次乘法。当n较大时两者的差异是明显的。)
#include 50、f", &x);
printf("y = %lf\n",
(x <= 0)?
sqrt(a * a + x * x)
: ( (3 * a * a * x + 4) * a * x - 1 )
);
}
4.(一般教材当然认为这种题目应当用双重循环,对a、b的所有也许取值情况所有判断一下不定方程是否成立。对于复杂一点的方程也许不得不如此,但是这儿用那种办法显然笨死了!对每个a的取值,计算相应的b,然后看b是否符合条件这不就够了吗?记住由于求b用了整数除法,所以得到的b只是真正的解的整数部分。所以在判断b是否在15~36之间的同时还要检查b是不是真的是原方程






