《C语言程序设计》(谭浩强第五版) 第4章 选择结构程序设计 习题解析与答案


你也可以上程序咖(https://meta.chengxuka.com),打开大学幕题板块,不但有答案,讲解,还可以在线答题。

WX20220412-135428@2x

题目1:什么是算术运算?什么是关系运算?什么是逻辑运算?

算术运算:

算术运算即“四则运算”,是加法、减法、乘法、除法、乘方、开方等几种运算的统称。

其中加减为一级运算,乘除为二级运算,乘方、开方为三级运算。在一道算式中,如果有多级运算存在,则应先进行高级运算,再进行低一级的运算。

C语言中的算熟运算符包括:+、-、*、/、++、--、% 等种类。

如果只存在同级运算;则从左至右的顺序进行;如果算式中有括号,则应先算括号里边,再按上述规则进行计算。

示例:$ (1 + 1)^{2} * 4+5 * 3$

解析:

先进行括号内运算1+1,然后进行乘方运算得到结果4.
接下来与4相乘,得到结果16
因为乘法优先级大于加法,因此先进行5*3,得到结果15
最终相加得到结果31
结果:31

关系运算:

关系的基本运算有两类:一类是传统的集合运算(并、差、交等),另一类是专门的关系运算(选择、投影、连接、除法、外连接等),而在C语言中,关系运算通常被认为是比较运算,将两个数值进行比较,判断比较结果是否符合给定的条件。

常见的关系运算符包括:<、<=、>、>=、==、!= 等种类。

其中,前4种关系运算符(<、<=、>、>= )的优先级别相同,后2种(==、!=)也相同。而前4种高于后2种。

例如, > 优先于 == 。而 > 与 < 优先级相同。
并且,关系运算符的优先级低于算术运算符,关系运算符的优先级高于赋值运算符(=)。

逻辑运算:

在逻辑代数中,有与、或、非三种基本逻辑运算。表示逻辑运算的方法有多种,如语句描述、逻辑代数式、真值表、卡诺图等。而在C语言中,逻辑运算通常用于使用逻辑运算符将关系表达式或其它逻辑量连接起来组成逻辑表达式用来测试真假值。

常见的逻辑运算符包括:&&、||、! 等种类

&&: 与是双目运算符,要求有两个运算对象,表示两个运算对象都成立,则结果为真,否则结果为假。

例如:(ay),表示(ay)同时成立则为真。

||:是双目运算符,要求有两个运算对象,表示两个运算对象只要任意一个成立,则结果为真,否则结果为假。

例如:(ay),表示(ay)两个对象中任意一个成立则结果为真。

!是单目运算符,只要求有一个运算对象,表示取运算对象反义,运算对象为真则结果为假,运算对象结果为假则结果为真。

例如:!(a>b),表示(a>b)成立时结果为假,不成立时结果为真。

若在一个逻辑表达式中包含多个逻辑运算符,则优先次序为: ! > && > ||。当然若一个逻辑表达式中包含括号括起来的子逻辑,则优先括号内的子逻辑判断。

示例:

(1>2)||(2>3)&&(4>3) 结果为0
!(1>2)||(2>3)&&(4>3)结果为1

注:&&优先级大于||,((2>3)&&(4>3))无法同时成立,则结果为假,然后与(1>2)结果进行逻辑或运算,两者都为假因此第一次结果为假。 而第二次!优先级最高,先对(1>2)的结果取逻辑非,得到结果为真,因此结果为真。

题目2:C语言中如何表示“真”和“假”?系统如何判断一个量的“真”和“假”?

答案:

对于逻辑表达式,若其值为“真",则以1表示,若其值为“假”,则以0表示。但是在判断一个逻辑量的值时,系统会以0作为“假”,以非0作为“真”。例如3 && 5的值为“真”,系统给出3 && 5的值为1。

题目3:写出下面各逻辑表达式的值。设a=3,b=4,c=5。
(1) a+b>c && b==c
(2) al|b十c && b-c
(3) !(a>b) && !c || 1
(4) !(x=a) && (y=b) && 0
(5) !(a+b)+c-1 && b十c/2

答案:

(1) 0
(2) 1
(3) 1
(4) 0
(5) 1

题目4:有3个整数a,b,c,由键盘输人,输出其中最大的数。

答案:

方法一:N-S图见图4.1

WX20220322-153007@2x

答案代码:

#include 
int main()
{
	int a, b, c;
	printf("请输入3个整数:");
	scanf("%d,%d,%d", &a, &b, &c);
	if (a < b)
		if (b < c)
			printf("max=%d\n", c);
		else
			printf("max=%d\n", b);
	else if (a < c)
		printf("max=%d\n", c);
	else
		printf("max=%d\n", a);
	return 0;
}

运行结果:

WX20220322-160216@2x

方法二:使用条件表达式,可以使程序更简明、清晰。

#include 
int main()
{
	int a, b, c, temp, max;
	printf("请输入3个整数:");
	scanf("%d,%d,%d", &a, &b, &c);
	temp = (a > b) ? a : b;		 //将a和b中的大者存入temp中
	max = (temp > c) ? temp : c; //将a和b中的大者与c比较,取最大者
	printf("3个整数的最大数是%d\n", max);
	return 0;
}

运行结果:

WX20220322-160958@2x

题目5:从键盘输入一个小于1000的正数,要求输出它的平方根(如平方根不是整数,则输出其整数部分)。要求在输入数据后先对其进行检查是否为小于1000 的正数。若不是,则要求重新输入。

解:答案代码:

#include 
#include 
#define M 1000
int main()
{
	int i, k;

	printf("请输入一个小于%d的整数i:", M);
	scanf("%d", &i);
	if (i > M)
	{
		printf("输人的数据不符合要求,请重新输入一个小于%d的整数i;", M);
		scanf("%d", &i);
	}
	k = sqrt(i);
	printf("%d的平方根的整数部分是%d\n", i, k);
	return 0;
}

运行结果:

①第一次:输人正确数据。

WX20220322-161634@2x

②第二次:输人不正确数据。

WX20220322-161843@2x

讨论:题目要求输人的数小于1000,今为了增加程序的灵活性,定义符号常量M为1000,如果题目要求输入的数小于10000,只须修改define指令即可,不必修改主函数。

用if语句检查输入的数是否符合要求,如果不符合要求应进行相应的处理。从上面的程序看来是很简单的,但在实际应用中是很有用的。因为在程序提供用户使用后,不能保证用户输入的数据都是符合要求的。假若用户输人了不符合要求的数据怎么办?如果没有检查和补救措施,程序是不能供实际使用的。

本程序的处理方法是:提醒用户“输人的数据错了”,要求重新输入。但只提醒一次,再错了怎么办?在学习了第5章循环之后,可以将程序改为多次检查,直到正确输人为止。程序如下:

#include 
#include 
#define M 1000
int main()
{
	int i, k;
	printf("请输入一个小于%d的整数i:", M);
	scanf("%d", &i);
	while (i > M)
	{
		printf("输入的数据不符合要求,请重新输入一个小于%d的整数i:", M);
		scanf("%d", &i);
	}
	k = sqrt(i);
	printf("%d的平方根的整数部分是%d\n", i, k);
	return 0;
}

运行结果:

WX20220322-162341@2x

多次输入不符合要求的数据,均通不过,直到输入符合要求的数据为止。

这种检查手段是很重要的,希望读者能真正掌握。本例只是示意性的,程序比较简单。有了此基础,读者根据此思路完全可以做到对任何条件进行检查处理,使程序能正常运行,万无一失。

题目6:有一个函数:
$$
y =
\begin{cases}
x + y= 1 & (x \lt 1) \
2x - 1 & (1 \le x \lt 10) \
3x - 11 & (x \le 10)
\end{cases}
$$

写程序,输入 x 的值,输出 y 相应的值。

答案代码:

#include 
#include 
#define M 1000
int main()
{
	int x, y;
	printf("输入x:");
	scanf("%d", &x);
	if (x < 1) // x<1
	{
		y = x;
		printf("x=%3d,  y=x=%d\n", x, y);
	}
	else if (x < 10) // 1= = 10
	{
		y = 3 * x - 11;
		printf("x=%d,  y=3*x-11=%d\n", x, y);
	}
	return 0;
}

运行结果:

WX20220322-170908@2x

WX20220322-170930@2x

WX20220322-171057@2x

题目7:有一个函数:
$$
y =
\begin{cases}
-1 & (x \lt 0) \
0 & (x = 0) \
1 & (x \gt 0)
\end{cases}
$$

有人分别编写了以下两个程序,请分析它们是否能实现题目要求。不要急于,上机运行程序,先分析上面两个程序的逻辑,画出它们的流程图,分析它们的运行情况。然后上机运行程序,观察并分析结果。

(1)

#include 
int main()
{
	int x, y;
	printf("enter x:");
	scanf("%d", &x);
	y = -1;
	if (x != 0)
		if (x > 0)
			y = 1;
		else
			y = 0;
	printf("x=%d,y=%d\n", x, y);
	return 0;
}

解:程序(1)的流程图见图4. 2。

它不能实现题目的要求。如果输人的x<0,则输出y=0。请注意else 与if 的配对关系。程序(1)中的else子句是和第9行的内嵌的if语句配对,而不与第8行的if语句配对。

WX20220322-174507@2x

运行结果:

WX20220322-175828@2x

x的值为-6,输出y=0,结果显然不对。

(2)

#include 
int main()
{
	int x, y;
	printf("enter x:");
	scanf("%d", &x);
	y = 0;
	if (x >= 0)
		if (x > 0)
			y = 1;
		else
			y = -1;
	printf("x=%d,y=%d\n", x, y);
	return 0;
}

解:程序(2)的流程图见图4.3。

WX20220322-180100@2x

它也不能实现题目的要求。如果输入的x<0,则输出y=0。

运行结果:

WX20220322-180205@2x

x的值为-4,输出y=0,结果显然不对。程序(2)中的else子句是和第9行的内嵌的if语句配对,而不与第8行的if语句配对。

一定要注意 if 与 else 的配对关系。配对关系不随 if 和 else 所出现的列的位置而改变,例如程序(2)中的else与第8行的 if 写在同一列,但 else 并不因此而与第8行的if语句配对,它只和在它前面的离它最近的 if 配对。

请和教材第 4 章例 4.5 程序对比分析,进一步理解 if-else 的配对规则。

为了使逻辑关系清晰,避免出错,一般把内嵌的 if 语句放在外层的 else 子句中(如例 4.5 中程序1 那样),这样由于有外层的 else 相隔,内嵌的 else 不会被误认为和外层的 if 配对,而只能与内嵌的 if 配对,这样就不会搞混,若像本习题的程序(1)和程序(2)那样写就很容易出错。

可与本章例 4.5 中介绍的程序进行对比分析。

题目8:给出一百分制成绩,要求输出成绩等级'A'、'B'、'C'、'D'、'E'。90 分以上为'A',80~89分为'B' ,70~70分为'C' ,60~69分为'D' ,60分以下为'E'。

解:答案代码:

#include 
int main()
{
	float score;
	char grade;
	printf("请输入学生成绩:");
	scanf("%f", &score);
	while (score > 100 || score < 0)
	{
		printf("\n输入有误,请重输");
		scanf("%f", &score);
	}
	switch ((int)(score / 10))
	{
	case 10:
	case 9:
		grade = 'A';
		break;
	case 8:
		grade = 'B';
		break;
	case 7:
		grade = 'C';
		break;
	case 6:
		grade = 'D';
		break;
	case 5:
	case 4:
	case 3:
	case 2:
	case 1:
	case 0:
		grade = 'E';
	}
	printf("成绩是%5.1f,相应的等级是%c\n", score, grade);
	return 0;
}

运行结果:

WX20220322-182529@2x

WX20220322-182554@2x

说明:对输入的数据进行检查,如小于0或大于100,要求重新输入。(int)( score/10)的作用是将(score/10)的值进行强制类型转换,得到一个整型值。例如,当score的值为78时,(int) (score/10)的值为7。然后在switch语句中执行case 7中的语句,使grade= 'C'。

题目9:给一个不多于5位的正整数,要求:

①求出它是几位数;

②分别输出每一位数字;

③按逆序输出各位数字,例如原数为321,应输出123。

解:

#include 
int main()
{

	int num, indiv, ten, hundred, thousand, ten_thousand, place; //分别代表个位、十位、百位、千位.万位和位数
	printf("请输入一个整数(0~99999):");
	scanf("%d", &num);
	if (num > 9999)
		place = 5;
	else if (num > 999)
		place = 4;
	else if (num > 99)
		place = 3;
	else if (num > 9)
		place = 2;
	else
		place = 1;
	printf("位数:%d\n", place);
	printf("毎位数字为:");
	ten_thousand = num / 10000;
	thousand = (int)(num - ten_thousand * 10000) / 1000;
	hundred = (int)(num - ten_thousand * 10000 - thousand * 1000) / 100;
	ten = (int)(num - ten_thousand * 10000 - thousand * 1000 - hundred * 100) / 10;
	indiv = (int)(num - ten_thousand * 10000 - thousand * 1000 - hundred * 100 - ten * 10);
	switch (place)
	{
	case 5:
		printf("%d,%d,%d,%d,%d", ten_thousand, thousand, hundred, ten, indiv);
		printf("\n反序数字为:");
		printf("%d%d%d%d%d\n", indiv, ten, hundred, thousand, ten_thousand);
		break;
	case 4:
		printf("%d,%d,%d,%d", thousand, hundred, ten, indiv);
		printf("\n反序数字为:");
		printf("%d%d%d%d\n", indiv, ten, hundred, thousand);
		break;
	case 3:
		printf("%d,%d,%d", hundred, ten, indiv);
		printf("\n反序数字为:");
		printf(" %d% d% d(n", indiv, ten, hundred);
		break;
	case 2:
		printf("%d,%d", ten, indiv);
		printf("\n反序数字为:");
		printf("%d%d\n", indiv, ten);
		break;
	case 1:
		printf("%d", indiv);
		printf("\n反序数字为:");
		printf("%dn", indiv);
		break;
	}
	return 0;
}

运行结果:

WX20220322-184708@2x

题目10:企业发放的奖金根据利润提成。利润 I 低于或等于 100 000 元的,奖金可提成10%;利润高于100 000 元,低于200 000元(100 0001 000 000时,超过1 000 000元的部分按1%提成。从键盘输入当月利润 I,求应发奖金总数。

要求:

(1)用if语句编程序;

(2)用 switch 语句编程序。

解:

(1)用 if 语句编程序。

答案代码:

#include 
int main()
{

	int i;
	double bonus, bon1, bon2, bon4, bon6, bon10;
	bon1 = 100000 * 0.1;
	bon2 = bon1 + 100000 * 0.075;
	bon4 = bon2 + 100000 * 0.05;
	bon6 = bon4 + 100000 * 0.03;
	bon10 = bon6 + 400000 * 0.015;
	printf("请输入利润i:");
	scanf("%d", &i);
	if (i <= 100000)
		bonus = i * 0.1;
	else if (i <= 200000)
		bonus = bon1 + (i - 100000) * 0.075;
	else if (i <= 400000)
		bonus = bon2 + (i - 200000) * 0.05;
	else if (i <= 600000)
		bonus = bon4 + (i - 400000) * 0.03;
	else if (i <= 1000000)
		bonus = bon6 + (i - 600000) * 0.015;
	else
		bonus = bon10 + (i - 1000000) * 0.01;
	printf("奖金是∶%10.2f\n", bonus);
	return 0;
}

运行结果:

WX20220323-094053@2x

此题的关键在于正确写出每一区间的奖金计算公式。例如利润在 100 000~200 000元时,奖金应由两部分组成∶

①利润为 100 000元时应得的奖金,即 100 000元×0.1。

②100 000元以上部分应得的奖金,即(num一100 000)×0.075元。

同理,200 000~400 000 元这个区间的奖金也应由两部分组成:

①利润为 200 000元时应得的奖金,即 100 000×0.1+100 000×0.075。

②200 000元以上部分应得的奖金,即(num—200 000)×0.05元。

程序中先把100 000元、200 000元、400 000元、600 000元、1 000 000元各关键点的奖金计算出来,即 bonl1,bon2,bon4,bon6 和 bonl0。然后再加上各区间附加部分的奖金即可。

(2)用 switch 语句编程序。

N-S图见图4.4。

WX20220323-094404@2x

答案代码:

#include 
int main()
{

	int i;
	double bonus, bon1, bon2, bon4, bon6, bon10;
	int branch;
	bon1 = 100000 * 0.1;
	bon2 = bon1 + 100000 * 0.075;
	bon4 = bon2 + 200000 * 0.05;
	bon6 = bon4 + 200000 * 0.03;
	bon10 = bon6 + 400000 * 0.015;
	printf("请输入利润 i∶");
	scanf("%d", &i);
	branch = i / 100000;
	if (branch > 10)
		branch = 10;
	switch (branch)
	{
	case 0:
		bonus = i * 0.1;
		break;
	case 1:
		bonus = bon1 + (i - 100000) * 0.075;
		break;

	case 2:
	case 3:
		bonus = bon2 + (i - 200000) * 0.05;
		break;
	case 4:
	case 5:
		bonus = bon4 + (i - 400000) * 0.03;
		break;
	case 6:
	case 7:
	case 8:
	case 9:
		bonus = bon6 + (i - 600000) * 0.015;
		break;
	case 10:
		bonus = bon10 + (i - 1000000) * 0.01;
	}
	printf("奖金是 %10.2f\n", bonus);
	return 0;
}

运行结果:

WX20220323-095110@2x

题目11:输入 4个整数,要求按由小到大的顺序输出。?解∶此题采用依次比较的方法排出其大小顺序。在学习了循环和数组以后,可以掌握更多的排序方法。

程序如下∶

#include 
int main()
{

	int t, a, b, c, d;
	printf("请输入4个数∶");
	scanf("%d,%d,%d,%d", &a, &b, &c, &d);
	printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);
	if (a > b)
	{
		t = a;
		a = b;
		b = t;
	}
	if (a > c)
	{
		t = a;
		a = c;
		c = t;
	}
	if (a > d)
	{
		t = a;
		a = d;
		d = t;
	}
	if (b > c)
	{
		t = b;
		b = c;
		c = t;
	}
	if (b > d)
	{
		t = b;
		b = d;
		d = t;
	}
	if (c > d)
	{
		t = c;
		c = d;
		d = t;
	}
	printf("排序结果如下∶\n");
	printf("%d %d %d %d \n", a, b, c, d);
	return 0;
}

运行结果:

WX20220323-095506@2x

题目12:有4个圆塔,圆心分别为(2,2)、(一2,2)、(—2,一2)、(2,一2),圆半径为1,见图 4.5。这 4个塔的高度为10m,塔以外无建筑物。今输入任一点的坐标,求该点的建筑高度(塔外的高度为零)。

WX20220323-095707@2x

解:N-S图见图 4.6。

WX20220323-095737@2x

答案代码:

#include 
int main()
{

	int h = 10;
	float x1 = 2, y1 = 2, x2 = -2, y2 = 2, x3 = -2, y3 = -2, x4 = 2, y4 = -2, x, y, d1, d2, d3, d4;
	printf("请输入一个点(x,y)∶");
	scanf("%f,%f", &x, &y); //求该点到各中心点距离
	d1 = (x - x4) * (x - x4) + (y - y4) * (y - y4);
	d2 = (x - x1) * (x - x1) + (y - y1) * (y - y1);
	d3 = (x - x2) * (x - x2) + (y - y2) * (y - y2);
	d4 = (x - x3) * (x - x3) + (y - y3) * (y - y3);
	if (d1 > 1 && d2 > 1 && d3 > 1 && d4 > 1)
		h = 0; //判断该点是否在塔外
	printf("该点高度为%d\n", h);
	return 0;
}

运行结果:

WX20220323-101800@2x

WX20220323-101914@2x

关于闰年问题的说明:

在教材第 4章中举了计算闰年的例子,有的读者对闰年规则不清楚,纷纷来信询问。因此,有必要在此对闰年的规定作一些说明:

地球绕太阳转一周的实际时间为365 天5小时 48 分 46 秒。如果一年只有 365天,每年就多出5个多小时。4年多出的23小时15分4秒,差不多等于一天。于是决定每4年增加1天。但是,它比一天 24小时又少了约45分钟。如果每100年有25个闰年,就少了18 时 43分20秒,这就差不多等于一天了,这显然是不合适的。

可以算出,每年多出5小时48分46秒,100年就多出581小时16分40秒。而 25个闰年需要 25×24=600 小时。581小时16分40秒只够 24个闰年(24×24=576 小时),于是决定每100年只安排24 个闰年(世纪年不作为闰年)。但是这样每 100年又多出5小时16 分40秒(581小时16分40秒—576小时),于是又决定每 400年增加一个闰年。这样就比较接近实际情况了。

根据以上情况,决定闰年按以下规则计算:

闰年应能被 4整除(如 2004年是闰年,而 2001年不是闰年),但不是所有能被4 整除的年份都是闰年。在能被 100 整除的年份中,只有同时能被 400 整除的年份才是闰年(如2000年是闰年),能被100整除而不能被400整除的年份(如 1800、1900、2100)不是闰年。这是国际公认的规则。只说"能被 4整除的年份是闰年"是不准确的。

教材中介绍的方法和程序是正确的。