C程序设计(第五版)-第5章 循环结构程序设计课后习题答案

1.请画出例5.6中给出的3个程序段的流程图

2.请补充例5. 7程序,分别统计当“fabs(t)>= le- 6”和“fabs(t)> = le- 8”时执行循环体的次数。

fabs(t)>= le- 6 ,示例代码

# include <stdio.h>
# include <math.h>

int main()
{
	int sign = 1;
	double pi = 0.0, term = 1.0;
	int n = 0;

	while (fabs(term) >= 1e-6)
	{
		n++;
		term = 1.0 / (2 * n - 1)*sign;
		pi += term;
		sign = -sign;
	}
	pi *= 4;
	printf("pi的近似值是%lf\n", pi);
	printf("循环体循环了%d次\n", n);
	return 0;
}

fabs(t)> = le- 8,示例代码

# include <stdio.h>
# include <math.h>

int main()
{
	int sign = 1;
	double pi = 0.0, term = 1.0;
	int n = 0;

	while (fabs(term) >= 1e-8)
	{
		n++;
		term = 1.0 / (2 * n - 1)*sign;
		pi += term;
		sign = -sign;
	}
	pi *= 4;
	printf("pi的近似值是%lf\n", pi);
	printf("循环体循环了%d次\n", n);
	return 0;
}

3.输人两个正整数m和n,求其最大公约数和最小公倍数

答案解析:

该题题目直接使用“辗转相除法”来求解最大公约数,以除数和余数反复做除法运算,当余数为 0 时,就取得当前算式除数为最大公约数。

最大公约数和最小公倍数之间的性质:两个自然数的乘积等于这两个自然数的最大公约数和最小公倍数的乘积。所以,当我们求出最大公约数,就可以很轻松的求出最小公倍数。

#include <stdio.h>
#include <windows.h>
int main()
{
    printf("------------------\n");
    int p, r, n, m, temp;
    printf("请输入两个正整数n,m:");
    scanf("%d%d,", &n, &m);

    //调整n保存较大的值
    if (n < m)
    {
        temp = n;
        n = m;
        m = temp;
    }

    p = n * m;
    while (m != 0)
    {
        r = n % m;
        n = m;
        m = r;
    }
    printf("它们的最大公约数为:%d\n", n);
    printf("它们的最小公倍数为:%d\n", p / n);

    return 0;
}

4.输人一行字符,分别统计出其中英文字母、空格、数字和其他字符的个数。

答案解析:

该题可以调用getchar函数,从stdin流中读入一个字符,当输入多个字符时,getchar()再执行时就会直接从缓冲区中读取了。等同于getc(stdin)。所以,我们循环调用getchar,直到将标准输入的内容读到换行符\n为止。同时判断,读取到的字符是英文字母、空格、数字或者其他字符,并计数;

#include <stdio.h>
#include <windows.h>
int main()
{
    printf("------------------\n");
    // 统计英文字母、空格、数字和其他字符数量,读到换行符\n截止
    char c;
    int eng_char = 0, space_char = 0, digit_char = 0, other_char = 0;

    printf("请输入一个字符:\n");
    while ((c = getchar()) != '\n')
    {
        if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
        {
            eng_char++;
        }
        else if (c == ' ')
        {
            space_char++;
        }
        else if (c >= '0' && c <= '9')
        {
            digit_char++;
        }
        else
        {
            other_char++;
        }
    }

    printf("英文%d个,空格%d个,数字%d个,其他字符%d个", eng_char, space_char, digit_char, other_char);

    return 0;
}

5.求Sn=a+aa+aaa+…na 之值,其中a是一个数字,n表示a的位数,n由键盘输入。例如:

2+22+222+2222+22222 (此时n=5)

答案解析:

该题目可以将数字拆分为 a * 10^n + 前一个数字,例如:

2 = 2 * 10^0 + 0 : 默认2的前一个数字为0,也就是没有任何值

22 = 2 * 10^1 + 2 : 22的前一个数字为2

222 = 2*10^2 + 22 :222的前一个数字为22

以此类推…

所以,在每次循环的时候,需要保存下,上一次结果的值,方便下一次计算

还需要使用到C库当中使用的pow函数,来计算某个数的n次方,我们在该题目当中使用的是10的n次方,n随着循环的次数,以此递增。

#include <stdio.h>
#include <windows.h>
#include <math.h>

int main()
{
    printf("------------------\n");
    int n;
    double a, s = 0.0, temp = 0.0;
    printf("请输入要计算的数字a:\n");
    scanf("%d", &a);
    printf("请输入要计算的次数n:\n");
    scanf("%d", &n);

    for (int i = 0; i < n; i++)
    {
        temp += a * pow(10, i);
        s += temp;
    }

    printf("结果:%d", s);

    return 0;
}

6.求

答案解析:

该题需要从1循环到20,依次求出每一个数字阶乘的结果。所以在代码当中需要有两个循环,大循环从1到20,保证1到20个数字都被循环到,小循环里计算N阶乘,累加求和。注意:对于20的阶乘已经超出了int类型能过表示的数字范围,所以在代码当中使用double类型

#include <stdio.h>
#include <windows.h>
int main()
{
    printf("------------------\n");
    double x, temp;
    for (int i = 1; i <= 20; i++)
    {
        temp = 1;
        for (int j = i; j > 0; j--)
        {
            temp *= j;
        }
        x += temp;
    }

    printf("1-20的阶乘之合:%f", x);

    return 0;
}

7.

对于第一个式子而言,指的是求从1到100的和。每个数字为整数,求和也为整数

对于第二个式子而言,指的是求从12到502的和。每个数字为整数,求和也为整数。

对于第三个式子而言,指的是求从1/k的和。每个数字不是整数,求和也不是整数。

综上所述:求和结果不是整数,所以定义求和变量是需要定义为带有精度的变量double

该题目,最大的求和是从从1到100,所以需要一个循环,从1遍历到100。针对第一种情况,则遍历100次停下来。针对第二种情况,则遍历50次的时候停下来,针对第三种情况,则遍历10遍就停下来。

最后,在遍历每一个数字的时候,针对三种不同的情况求和。最后将三种不同请求的和加起来就是总体的和

#include <stdio.h>
#include <windows.h>
#include <math.h>
int main()
{
    printf("------------------\n");

    double x, y, z, r;
    // 1-100的合
    for (int i = 1; i <= 100; i++)
    {
        x += i;
        //遍历50次就不在执行情况2
        if (i <= 50)
        {
            y += pow(i, 2);
        }
        //遍历10次就不在执行情况3
        if (i <= 10)
        {
            z += 1.0 / i;
        }
    }
    r = x + y + z;
    // 结果47977.928968
    printf("结果%f", r);
    return 0;
}

8.输出所有的“水仙花数”,所谓“水仙花数”是指一个3位数,其各位数字立方和等于该数本身。例如,153是水仙花数,因为153=13+53+3^3。

答案解析:

从题目当中得到”水仙花数“为一个3位数,则范围确定为[100, 999]。另外需要获取该数字的百位数字,十位数字,个位数字相加起来等于该数本身,则我们需要使用到%除的方式,来获取每一个位权的数字。

#include <stdio.h>
#include <windows.h>
#include <math.h>
int main()
{
    printf("------------------\n");
    int a, b, c;
    for (int i = 100; i < 1000; i++)
    {

        a = i % 10;             // 个位
        b = (i / 10) % 10;      // 十位
        c = (i / 10 / 10) % 10; // 百位

        // 结果 水仙花数:153,370,371,407
        if ((pow(a, 3) + pow(b, 3) + pow(c, 3)) == i)
        {
            printf("水仙花数:%d\n", i);
        }
    }

    return 0;
}

9.一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如,6的因子为1,2,3,而6=1+2+3,因此6是“完数”。编程序找出1000之内的所有完数,并按下面格式输出其因子: 6 its factors are 1,2,3

#include <stdio.h>
#include <windows.h>
int main()
{
    printf("------------------\n");
    int sum, factor, data;
    for (data = 2; data <= 1000; data++)
    {
        sum = 1; // 1一定是因子
        for (int factor = 2; factor <= data / 2; factor++)
        {
            if (data % factor == 0)
            {
                sum += factor;
            }
        }

        // 是“完数”
        if (sum == data)
        {
            printf("%d its factors are ", data);
            for (int factor = 2; factor <= data / 2; factor++)
            {
                if (data % factor == 0)
                {
                    printf("%d,", factor);
                }
            }
            printf("\n");
        }
        // 结果
        //         6 its factors are 2,3,
        // 28 its factors are 2,4,7,14,
        // 496 its factors are 2,4,8,16,31,62,124,248,
    }

    return 0;
}

10.有一个分数序列,求出这个数列的前20项之和。

从题目当中可以看出来,下一个分式当中的分子为上一个分式中分子和分母的和,分母为上一个分式的分子。通过这个规律不难推出下一个分式的分子和分母,需要注意的是,保存分式的结果不能使用到整数,因为有可能会有小数的存在,所以我们需要选用浮点数double

#include <stdio.h>
#include <windows.h>
#define COUNT 20

int main()
{
    printf("------------------\n");
    double sum = 0.0, fenzi, fenmu;
    for (int i = 0; i < COUNT; i++)
    {

        if (i == 1)
        {
            fenzi = 2;
            fenmu = 1;
        }
        else
        {
            int temp = fenzi;
            fenzi = fenmu + fenzi;
            fenmu = temp;
        }

        sum += (fenzi / fenmu);
    }

    printf("%f", sum);

    return 0;
}

11.一个球从100m高度自由落下,每次落地后反弹回原高度的一半,再落下,再反弹。求它在第10次落地时共经过多少米,第10次反弹多高。

答案解析:

该题目需要循环10次,在每一循环的时候,需要将下落的高度和回弹的高度加起来。需要注意的点,第10次下落不需要在计算回弹的距离了,所以需要特殊处理下。在计算每次高度的时候,会有小数存在,所以需要选用浮点数

#include <stdio.h>
#include <windows.h>
#define COUNT 10
int main()
{   
    printf("------------------\n");
    //总高度
	double total_m = 100.0;
	//小球经历的米数
	double total_sum = 0.0;
    for (int i = 0; i < COUNT; i++)
    {
        total_sum += total_m;
        total_m /=2;
        total_sum += total_m;
    }
    //不需要计算第10次的反弹高度,所以减去
	total_sum -= total_m;
	printf("小球总共经历%lf米, 第10次反弹%lf米\n", total_sum, total_m);
    // 小球总共经历299.609375米, 第10次反弹0.097656米

    return 0;
}

12.猴子吃桃问题。猴子第1天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第2天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,就只剩一个桃子了。求第1天共摘多少个桃子。

答案解析:

从题面上来看,可以推出,后一天的桃子数量 = 前一天桃子数量 / 2 - 1。所以,该公式也可以写成前一天的桃子数量 = (后一天桃子数量+1) * 2。所以我们知道了第10天剩余桃子的数量,则可以依次推算出桃子的前一天桃子的总数。需要注意的点,猴子只是吃了9天,所以,我们只需要遍历9次就可以了。

#include <stdio.h>
#include <windows.h>
int main()
{
    printf("------------------\n");
    int sum = 1;
    for (int i = 0; i < 9; i++)
    {
        sum = (sum + 1) * 2;
    }

    // 桃子一共1534个
    printf("桃子一共%d个", sum);
    return 0;
}

13.用迭代法求x=根号a。求平方根的迭代公式为

要求前后两次求出的x的差的绝对值小于10^{-5}。

#include <stdio.h>
#include <math.h>

int main()
{
	float a, x0, x1;
	printf("请输入一个正数: ");
	scanf("%f", &a);
	x0 = a / 2;
	x1 = (x0 + a / x0) / 2;
	do
	{
		x0 = x1;
		x1 = (x0 + a / x0) / 2;
	} while (fabs(x0 - x1) >= 1e-5);
	printf("[%f] 的平方根为 [%f]\n", a, x1);
	return 0;
}

14.用牛顿迭代法求下面方程在1.5附近的根:

2*x3-4*x2+3*x-6=0

#include <stdio.h>
#include <math.h>

int  main()
{
	double x1, x0, f, f1;
	x1 = 1.5;
	do
	{
		x0 = x1;
		f = ((2 * x0 - 4) * x0 + 3) * x0 - 6;
		f1 = (6 * x0 - 8) * x0 + 3;
		x1 = x0 - f / f1;
	} while (fabs(x1 - x0) >= 1e-5);
	printf("方程在1.5附近的根为:%lf\n", x1);
	return 0;
}

15.用二分法求下面方程在(-10,10)的根:

2*x3-4*x2+3*x-6=0

答案解析:

将区间划分为两部分,记录区间左右端点,得到中点。每次运算将中点带入方程进行运算,求得结果,进行分析:

结果 > 0:将中位数赋值给右端点

结果 < 0:将中位数赋值给左端点

以此类推…

fabs函数是一个求绝对值的函数,求出x的绝对值,和数学上的概念相同;

le-5:1 0 − 5 10^{-5}10−5,即0.00001

#include<stdio.h>
#include<math.h>

int main()
{
	double left = -10, right = 10, mid;
	double temp = 10;
	while (fabs(temp) > 1e-5)
	{
		mid = (left + right) / 2;
		//((2x - 4)*x + 3) * x - 6 ==> 2x^3 - 4x^2 + 3x -6
		temp = ((2 * mid - 4) * mid + 3) * mid - 6;

		if (temp > 0)
		{
			right = mid;
		}
		else if (temp < 0)
		{
			left = mid;
		}
	}
	printf("在(-10,10)的根为:%lf", mid);
	return 0;
}

16.输出以下图案:

答案解析:

该题目需要关心当前行对应的从最左边到第一颗*的空格数量以及星星数量。将该题分为两个部分,前面4行和后面3行来进行拆分。

前4行中:

第一行:行号为0, 空格数为3,星星数量为1;

第二行:行号为1, 空格数为2, 星星数量为3;

第三行:行号为2, 空格数为1, 星星数量为5;

第四行:行号为3, 空格数为0,星星数量为7;

则我们可以推出两组关系,即行号和空格数量关系为:空格数 = 3 - 行号 。行号与星星的关系为:星星数 = 2 * 行号 + 1

后三行中:

第一行:行号为0,空格数为1,星星数量为5;

第二行:行号为1, 空格数为2, 星星数量为3;

第三行:行号为2, 空格数为3,星星数量为1;

则我们推出两组关系,即行号与数量的关系:空格数 = 行号 + 1。行号与星星的关系:星星数 = 7 - 2 * (行号+1)

基于上面的关系,我们写出如下代码:

#include <stdio.h>

int main()
{
	int cur_row, space_count, start_count;
	//输出前4行内容
	for (cur_row = 0; cur_row < 4; cur_row++)
	{
		//计算当前行空格数量,并且进行打印
		for (space_count = 3 - cur_row; space_count > 0; space_count--)
		{
			printf(" ");
		}
		//计算当前行*数量,并且进行打印
		for (start_count = 2 * cur_row + 1; start_count > 0; start_count--)
		{
			printf("*");
		}
		printf("\n") ;
	}
	//输出后三行
	for (cur_row = 0; cur_row < 3; cur_row++)
	{
		for (space_count = cur_row + 1; space_count > 0; space_count--)
		{
			printf(" ");
		}

		for (start_count = 7 - 2 * (cur_row + 1); start_count > 0; start_count--)
		{
			printf("*");
		}
		printf("\n");
	}
	return 0;
}

17.两个乒乓球队进行比赛,各出3人。甲队为A,B,C 3人,乙队为X,Y,Z 3人。已抽签决定比赛名单。有人向队员打听比赛的名单,A说他不和X比,C说他不和X,Z比,请编程序找出3对赛手的名单。

答案解析:

从题面上得知,每队为3人,则隐含条件为队内三人是不能比赛的,并且A一定不会和X比,C一定不会X和Z比;则我们不难写出判断条件:

如果A和X比 或者 C和X比 或者 C和Z比 或者 A和B比 或者 A和C比 或者 B和C比,都是不可以的;所以我们只要穷举A比赛对象,B比赛对象,C比赛对象,判断上述条件就可以了;

#include <stdio.h>

int main()
{
	int A_battle, B_battle, C_battle;
	//如果A对战的对象从“X”到“Z”
	for (A_battle = 'X'; A_battle <= 'Z'; A_battle++)
	{
		//如果B对战的对象从“X”到“Z”
		for (B_battle = 'X'; B_battle <= 'Z'; B_battle++)
		{
			//如果C对战的对象从“X”到“Z”
			for (C_battle = 'X'; C_battle <= 'Z'; C_battle++)
			{
				//去除限制条件
				if (A_battle == 'X' || C_battle == 'X' || C_battle == 'Z' || B_battle == A_battle || B_battle == C_battle || A_battle == C_battle)
				{
					continue;
				}
				printf("A对%c,B对%c,C对%c", A_battle, B_battle, C_battle);
			}
		}
	}
	return 0;
}

C程序设计(第五版)-第1章 程序设计和C语言课后习题答案
C程序设计(第五版)-第2章 算法--程序的灵魂课后习题答案
C程序设计(第五版)-第3章 最简单的C程序设计—顺序程序设计课后习题答案
C程序设计(第五版)-第4章 选择结构程序设计课后习题答案
C程序设计(第五版)-第5章 循环结构程序设计课后习题答案
C程序设计(第五版)-第6章 利用数组处理批量数据课后习题答案
C程序设计(第五版)-第7章 用函数实现模块化程序设计课后习题答案

posted @ 2021-12-16 17:15  luckyangg  阅读(867)  评论(0)    收藏  举报