首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >收集飞花令碎片——C语言分支与循环语句(下)

收集飞花令碎片——C语言分支与循环语句(下)

作者头像
枫亭湖区
发布2025-11-13 09:06:50
发布2025-11-13 09:06:50
40
举报

前言

上一篇文章收集飞花令碎片——C语言分支与循环结构(上)已经跟大家全面讲解了分支与循环的基础知识,这一张会通过几个程序设计项目来锻炼逻辑思维能力,难度从难到易,大家可以根据自己的需求去练习

练习一:年龄划分

输⼊⼀个⼈的年龄 如果年龄<18岁,打印“少年” 如果年龄在18岁⾄44岁打印“⻘年” 如果年龄在45岁⾄59岁打印“中⽼年” 如果年龄在60岁⾄89岁打印“⽼年” 如果90岁及以上打印“⽼寿星”

代码语言:javascript
复制
#include <stdio.h>

int main() {
    int age = 0;
    scanf("%d", &age);

    if (age < 18) {
        printf("少年\n");
    } else {
        if (age <= 44) {
            printf("⻘年\n");
        } else {
            if (age <= 59) {
                printf("中⽼年\n");
            } else {
                if (age <= 89) {
                    printf("⽼年\n");
                } else {
                    printf("⽼寿星\n");
                }
            }
        }
    }

    return 0;
}

这道题只要你深入理解分支if语句加上一点点烧烤 只能说是

在这里插入图片描述
在这里插入图片描述

练习二:闰年的判断

  • 闰年判断的规则: 1. 能被4整除并且不能被100整除是闰年 2. 能被400整除是闰年
代码语言:javascript
复制
#inlclude <stdio.h>
int main()
{
	int yesr = 0;
	printf("请输入一个年份:");
	scanf_s("%d",&year);
	if((year%100!=0&&year%4==0)||(year%400==0)){
		printf("是闰年");
		}else{
			 printf("不是闰年");
			 }
}

练习三:操作符运算

代码1

代码语言:javascript
复制
#include <stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
return 0;
}

关键点:

  1. a++ 是后置递增,先使用 a 的值,然后再递增。
  2. && 是逻辑与运算符,具有短路特性。如果左边的表达式为假(0),右边的表达式不会计算。

执行过程:

  1. a++:先使用 a 的值 0,然后 a 自增为 1。因为 a 的初始值是 0,所以 a++ 的返回值是 0。
  2. 由于 && 的第一个操作数是 0(假),整个表达式的结果已经确定为 0,因此 ++b 和 d++ 不会执行。
  3. i 被赋值为 0。

打印时:

  1. a 已经自增为 1。
  2. b 和 d 没有被修改,保持原值。
  3. c 始终未被修改。

输出:

代码语言:javascript
复制
a = 1
b = 2
c = 3
d = 4

上⾯的代码执⾏结果是什么?如果把a的值改成1,结果⼜是什么?

代码语言:javascript
复制
int i = 0, a = 1, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;

执行过程:

  1. a++:先使用 a 的值 1,然后 a 自增为 2。a++ 的返回值是 1。
  2. 第一个 && 的操作数是 1(真),继续计算 ++b:
  3. ++b:b 先自增为 3,返回值是 3(非零,真)。
  4. 第二个 && 的操作数是 3(真),继续计算 d++:
  5. d++:先使用 d 的值 4,然后 d 自增为 5。d++ 的返回值是 4(非零,真)。
  6. 整个表达式的结果是 1(真),i 被赋值为 1。

打印时:

  1. a 已经自增为 2。
  2. b 已经自增为 3。
  3. d 已经自增为 5。
  4. c 未被修改。

输出:

代码语言:javascript
复制
a = 2
b = 3
c = 3
d = 5

代码2

代码语言:javascript
复制
#include <stdio.h>
int main()
{
int i = 0, a = 1, b = 2, c = 3, d = 4;
i = a++ || ++b || d++;
printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
return 0;
}
//上⾯的代码执⾏结果是什么?如果把a的值改成0,结果⼜是什么?

关键点:

  1. a++ 是后置递增,先使用 a 的值,然后再递增。
  2. || 是逻辑或运算符,具有短路特性。如果左边的表达式为真(非零),右边的表达式不会计算。

执行过程:

  1. a++:先使用 a 的值 1,然后 a 自增为 2。a++ 的返回值是 1。
  2. 由于 || 的第一个操作数是 1(真),整个表达式的结果已经确定为 1,因此 ++b 和 d++ 不会执行。
  3. i 被赋值为 1。

打印时:

  1. a 已经自增为 2。
  2. b 和 d 没有被修改,保持原值。
  3. c 始终未被修改。

输出:

代码语言:javascript
复制
a = 2
b = 2
c = 3
d = 4

如果将 a 的值改为 0:

代码语言:javascript
复制
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ || ++b || d++;

执行过程:

  1. a++:先使用 a 的值 0,然后 a 自增为 1。a++ 的返回值是 0。
  2. 第一个 || 的操作数是 0(假),继续计算 ++b:
  3. ++b:b 先自增为 3,返回值是 3(非零,真)。
  4. 由于 ++b 的结果是 3(真),第二个 || 的操作数 d++ 不会执行。
  5. 整个表达式的结果是 1(真),i 被赋值为 1。

打印时:

  1. a 已经自增为 1。
  2. b 已经自增为 3。
  3. d 未被修改。
  4. c 未被修改。

输出:

代码语言:javascript
复制
a = 1
b = 3
c = 3
d = 4

练习四:打印对应的星期几

代码语言:javascript
复制
#include <stdio.h>
int main()
{
int day = 0;
	scanf("%d", &day);
switch(day)
	{
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
		printf("⼯作⽇\n");
		break;
	case 6:
	case 7:
		printf("休息⽇\n");
		break;
	}
return 0;
}

进阶挑战题:

代码语言:javascript
复制
#include <stdio.h>
int main() {
    int a = 1, b = 0, c = -1;
    if (a++ && b++ || c++) {
        if (a-- || b-- && c--)
            printf("Block A: %d %d %d\n", a, b, c);
        else
            printf("Block B: %d %d %d\n", a, b, c);
    } else {
        printf("Block C: %d %d %d\n", a, b, c);
    }
    
    return 0;
}

终极问题:逐步分析每个表达式的求值过程和副作用

解:逐步分析代码执行过程

  • 初始值 a = 1,b = 0,c = -1
  • 第一个if条件:

计算 a++: 先用后增,表达式为1 计算a++&&b++ 由于a++为真,所以没有短路特性 b++为0 两者一真一假,所以表达式的值为0 计算a++&&b++||c++ c++为-1,表达式结果为真 左0右1,结果为真

  • 进入第一个if模块
  • 第二个if条件判断:

计算 a–: 使用 a 的当前值 2(真) 然后 a 自减为 1(副作用) 表达式结果:1由于 || 的左操作数为真,短路求值,不再计算 b-- && c– b 和 c 保持不变 整个表达式结果为 1(真) 进入 Block A

代码语言:javascript
复制
printf("Block A: %d %d %d\n", a, b, c);

考察点:

  1. 复杂表达式中的副作用序列点
  2. 运算符优先级与结合性的综合应用
  3. 嵌套条件语句的执行路径分析

接下来进入循环节点

请添加图片描述
请添加图片描述

练习五:在屏幕上打印 1~10 的值

代码语言:javascript
复制
#include <stdio.h>
int main()
{
int i = 1;
	while(i <= 10)
	{
	printf("%d ", i);
	
	i = i + 1;
	}
return 0;
}

练习六:逆序打印这个整数的每⼀位

例如: 输⼊:1234,输出:4 3 2 1 输⼊:521,输出:1 2 5

题目解析

  1. 要想得到n的最低位,可以使⽤n%10的运算,得到的余数就是最低位,如:1234%10得到4
  2. 要想去掉n的最低位,找出倒数第⼆位,则使⽤ n=n/10 操作就可以去掉最低位的,如: n=1234/10得到123,123相较于1234就去掉了最低位,123%10就得到倒数第⼆位3。
  3. 循环1和2两个步骤,在n变成0之前,就能到所有的位。
代码语言:javascript
复制
#include <stdio.h>
int main(){
	int num = 0;
	printf("请输入一个数字:");
	scanf_s("%d",&num);//scanf_s是Microsoft特有的安全版本,通常建议使用标准						的scanf函数,除非在特定环境下需要使用scanf_s。
		while(num){
					printf("%d",num%10);
					num /= 10;
				}
	return 0;
	}

练习七:计算1~100之间3的倍数的数字之和

代码语言:javascript
复制
#include <stdio.h>
int main(){

	int n = 3;
	int sum = 0;
	for (int i = 1; i <= 100; i++) {
		if (i % n == 0) {
			
			sum += i;
		}
	}
	printf("%d",sum);
	return 0;
}

练习八:计算一个整数是几位数

代码语言:javascript
复制
#include <stdio.h>
int main() {
	int n = 0;
	scanf_s("%d", &n);
	int sum = 0;
	do {
		sum++;
		n /= 10;

	} while (n != 0);
	printf("%d", sum);
	return 0;
}

练习九:找素数(重点)

  • 题目解析:
  1. 要从100 ~ 200之间找出素数,首先得有100 ~ 200之间的数,这⾥可以使用循环解决。
  2. 假设要判断i是否为素数,需要拿2 ~ i-1之间的数字去试除i,需要产⽣2 ~ i-1之间的数字,也可以使用循环解决。
  3. 如果2~i-1之间有数字能整除i,则i不是素数,如果都不能整除,则i是素数。

我们先来看看下面这段代码有没有问题

代码语言:javascript
复制
#include <stdio.h>
int main() {

	int j;
	scanf_s("%d", &j);

	for (int i = 2; i < j; i++) {
		if (i % j == 0) {
			printf("j不是素数");
			break;
		}
	}
	printf("j是素数");



	return 0;
}

在 for 循环中,如果发现 j 不是素数,程序会输出 “j不是素数” 并跳出循环。然而,无论 j 是否为素数,程序都会在循环结束后输出 “j是素数”。这会导致即使 j 不是素数,程序也会错误地输出 “j是素数”。

这时候就需要引入一个参数了

代码语言:javascript
复制
#include <stdio.h>

int main() {
    int j;
    scanf_s("%d", &j);

    int isPrime = 1; // 假设 j 是素数

    for (int i = 2; i < j; i++) {
        if (j % i == 0) {
            isPrime = 0; // j 不是素数
            break;
        }
    }

    if (isPrime) {
        printf("j是素数");
    } else {
        printf("j不是素数");
    }

    return 0;
}

优化建议

对于较大的数,可以通过优化循环条件来提高效率。例如,只需循环到 sqrt(j) 即可,因为如果 j 不是素数,它必定有一个因子小于或等于 sqrt(j)。

代码语言:javascript
复制
#include <stdio.h>
#include <math.h>

int main() {
    int j;
    scanf_s("%d", &j);

    int isPrime = 1; // 假设 j 是素数

    for (int i = 2; i <= sqrt(j); i++) {
        if (j % i == 0) {
            isPrime = 0; // j 不是素数
            break;
        }
    }

    if (isPrime) {
        printf("j是素数");
    } else {
        printf("j不是素数");
    }

    return 0;
}

接下来的练习就要开始上强度了

练习十:写⼀个猜数字游戏

  • 游戏要求:
  1. 电脑自动生成1~100的随机数
  2. 玩家猜数字,猜数字的过程中,根据猜测数据的大小给出大了或小了的反馈,直到猜对,游戏结束

随机数函数

rand

C语言提供了⼀个函数叫 rand,这函数是可以生成随机数的,rand函数会返回⼀个伪随机数,这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的大小是依赖编译器上实现的,但是⼤部分编译器上是32767。 rand函数的使用需要包含⼀个头⽂件是:stdlib.h

代码展示

代码语言:javascript
复制
int rand (void);

下面是两次随机数输出的结果

在这里插入图片描述
在这里插入图片描述

我们可以看到虽然⼀次运⾏中产⽣的5个数字是相对随机的,但是下⼀次运⾏程序⽣成的结果和上⼀次⼀模⼀样,这就说明有点问题。

如果再深入了解⼀下,我们就不难发现,其实 rand 函数⽣成的随机数是伪随机的,伪随机数不是真正的随机数,是通过某种算法⽣成的随机数。真正的随机数的是无法预测下⼀个值是多少的。⽽ rand 函数是对⼀个叫种⼦的基准值进行运算⽣成的随机数。

srand

C语⾔中⼜提供了⼀个函数叫 srand,⽤来初始化随机数的⽣成器的

代码语言:javascript
复制
void srand (unsigned int seed)

程序中在调⽤ rand 函数之前先调⽤ srand 函数,通过 srand 函数的参数seed来设置rand函数⽣成随机数的时候的种⼦,只要种⼦在变化,每次⽣成的随机数序列也就变化起来了。 那也就是说给srand的种⼦是如果是随机的,rand就能⽣成随机数

time

C语言中的time函数用于获取当前日历时间,通常以秒为单位表示自1970年1月1日00:00:00 UTC(即UNIX纪元)以来的时间。

time函数的时候需要包含头⽂件:time.h

代码展示

代码语言:javascript
复制
#include <stdio.h>
#include <time.h>

int main() {
    time_t current_time;
    time(&current_time);  // 获取当前时间
    printf("Current time: %ld\n", current_time);
    return 0;
}

进一步处理

time函数返回的时间通常是一个整数,表示自UNIX纪元以来的秒数。为了将其转换为更易读的格式,可以使用ctime

代码语言:javascript
复制
#include <stdio.h>
#include <time.h>

int main() {
    time_t current_time;
    time(&current_time); // 转换为可读格式
    printf("Current time:%ld\n",ctime(&current_time));
    return 0;
}

如果 timer 是 NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳

  • 那我们就可以让⽣成随机数的代码改写成如下:
代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
//使⽤time函数的返回值设置种⼦
//因为srand的参数是unsigned int类型,我们将time函数的返回值强制类型转换
srand((unsigned int)time(NULL));
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
return 0;
}
设置随机数的范围

如果要生成A~B的随机数,方法如下:

代码语言:javascript
复制
int num = rand() % (B - A + 1) + A;

生成 [0, N-1] 的随机数

代码语言:javascript
复制
int num = rand() % N;  // 范围:0 ~ N-1

生成 [1, N] 的随机数

代码语言:javascript
复制
int num = rand() % N + 1;  // 范围:1 ~ N

代码展示

  • 代码设计思路分析

  1. 输入一个数,就得到反馈,这时候我们可以用到do~while循环 所以我们main函数的基本格式就是:
代码语言:javascript
复制
int main(){
	do{
		}while();
return 0;
}
  1. 在do那里添加游戏菜单 menu函数编写(函数编写后面讲函数的时候会讲到的)
代码语言:javascript
复制
void menu()
{
printf("***********************\n");
printf("****** 1. play ******\n");
printf("****** 0. exit ******\n");
printf("***********************\n");
  1. 修改main函数
代码语言:javascript
复制
int main(){
int input = 0;
	do{
		menu();
		printf("请选择:");      //选择肯定直接选`switch`语句
		scanf("%d",&input);
		switch(input){
		case 1:
			printf("猜数字");
			game();				//游戏函数
			break;
		case 0:
			printf("退出游戏");
			break;
		default:
			printf("选择错误,请重新选择");
			break;
		}while(input);
	return 0;
	}
}
代码语言:javascript
复制
void game(){
		//生成一个0~100的随机数
		int r = rand()%(100+1);
		int guess = 0;
		int count = 5;
		
				while(count){
						printf("你还有%d次机会",count);
						printf("请猜出你的数字");
						scanf("%d",&guess);
						count--;
						
						if (guess < r) {
							printf("猜⼩了\n");
						} else if (guess > r) {
							printf("猜⼤了\n");
						} else {
							printf("恭喜你,猜对了\n");
							break;
						}
					}
		if (count == 0) {
       printf("你失败了,正确值是:%d\n", r);
 								}
				}

完整代码展示

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void game() {
    int r = rand() % (100 + 1);
    int guess = 0;
    int count = 5;

    while (count) {
        printf("\n你还有%d次机会\n", count);
        printf("请猜数字>:");
        scanf("%d", &guess);

        if (guess < r) {
            printf("猜⼩了\n");
        } else if (guess > r) {
            printf("猜⼤了\n");
        } else {
            printf("恭喜你,猜对了\n");
            break;
        }
        count--;
    }

    if (count == 0) {
        printf("你失败了,正确值是:%d\n", r);
    }
}

void menu() {
    printf("***********************\n");
    printf("****** 1. play ******\n");
    printf("****** 0. exit ******\n");
    printf("***********************\n");
}

int main() {
    int input = 0;
    srand((unsigned int)time(NULL));

    do {
        menu();
        printf("请选择:>");
        scanf("%d", &input);

        switch (input) {
            case 1:
                game();
                break;
            case 0:
                printf("游戏结束\n");
                break;
            default:
                printf("选择错误,重新选择\n");
                break;
        }
    } while (input);

    return 0;
}

练习十一:N人求最高分和平均分

本任务是键盘输入某班n个学生成绩,直至输入-1时结束,编程求出这n个学生的最高分以及平均分。

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

完整代码展示

代码语言:javascript
复制
#include <stdio.h>

int main() {
    int avg = 0, sum = 0, score = 0;
    int n = 0, max = 0;

    while (1) {
        printf("请输入第%d位的成绩:", n + 1);
        scanf_s("%d", &score);

        if (score == -1) {
            break;
        }

        if (score > max) {
            max = score;
        }

        sum += score;
        n++;
    }

    avg = sum / n;
    printf("平均分:%d\n", avg);
    printf("最高分:%d\n", max);

    return 0;
}

练习十二:求奇数阶乘和

代码语言:javascript
复制
#include <stdio.h>

int main() 
{
    int n = 0;
    scanf_s("%d", &n);  // 输入整数n

    long long sum = 0;  // 初始化阶乘和为0

    // 外层循环:计算1到n的阶乘和
    for (int i = 1; i <= n; i++) 
    {
        long long fac = 1;  // 初始化当前数的阶乘
        
        // 内层循环:计算i的阶乘
        for (int j = 1; j <= i; j++) 
        {
            fac *= j;
        }
        
        sum += fac;  // 将当前阶乘加入总和
    }

    // 输出结果
    printf("%d的阶乘和是%lld", n, sum);
    
    return 0;
}

练习十三:近似计算e

代码语言:javascript
复制
#include <stdio.h>

int main() {
    double e = 1.0;   // 使用 double 提高精度
    double fac = 1.0; // 阶乘也必须是浮点型
    int terms = 0;

    printf("输入计算的项数:");
    scanf_s("%d", &terms);  // 或者 scanf_s("%d", &terms);

    for (int i = 1; i <= terms; i++) {  // 注意是 i <= terms
        fac *= i;          // 计算 i! (1, 2, 6, 24, ...)
        e += 1.0 / fac;    // 加上 1/i!,注意 1.0 确保浮点除法
    }

    printf("e ≈ %.15f\n", e);  // 输出 e 的值,保留 15 位小数
    return 0;
}

练习十四:倒数阶乘正负交叉算法题(难)

这个问题要求计算一个交替正负的倒数阶乘序列的和,即: S = 1/1! - 1/2! + 1/3! - 1/4! + ... ± 1/n!

这一关可以有三种方法去

基本方法

代码语言:javascript
复制
#include <stdio.h>

int main() {
    double sum = 0.0;
    double fac = 1.0;  // 0! = 1
    int sign = 1;      // 初始符号为正
    
    int terms = 0;
    printf("请输入项数:");
    scanf("%d", &terms);  // 或scanf_s("%d", &terms)

    // 处理i=0的特殊情况
    sum += sign * (1.0 / fac);
    sign *= -1;

    for(int i = 1; i < terms; i++) {
        fac *= i;  // 计算i!
        sum += sign * (1.0 / fac);
        sign *= -1;  // 改变符号
    }

    printf("前%d项交替倒数阶乘和为: %.15f\n", terms, sum);
    return 0;
}
代码解析:
  • 变量初始化
代码语言:javascript
复制
double sum = 0.0;      // 存储最终的和
double fac = 1.0;      // 用于计算阶乘,初始为0! = 1
int sign = 1;          // 控制正负号,初始为1(正)
  • 用户输入
代码语言:javascript
复制
int terms = 0;
printf("请输入项数:");
scanf("%d", &terms);   // 获取用户输入的项数n

- **处理第一项(i=0)**

```c
sum += sign * (1.0 / fac);  // 计算第一项:1/0! = 1/1 = 1
sign *= -1;                 // 符号变为负,准备下一项
  • 循环计算后续项(i从1到terms-1)
代码语言:javascript
复制
for(int i = 1; i < terms; i++) {
    fac *= i;               // 计算i! (1!, 2!, 3!,...)
    sum += sign * (1.0 / fac);  // 加上当前项:±1/i!
    sign *= -1;             // 每次循环改变符号
}
  • 输出结果
代码语言:javascript
复制
printf("前%d项交替倒数阶乘和为: %.15f\n", terms, sum);
  • 示例计算过程(terms=4):
  1. i=0: sum = 0 + 1*(1/1) = 1.0, sign变为-1
  2. i=1: fac=11=1, sum=1 + (-1)(1/1)=0.0, sign变为1
  3. i=2: fac=12=2, sum=0 + 1(1/2)=0.5, sign变为-1
  4. i=3: fac=23=6, sum=0.5 + (-1)(1/6)≈0.3333, sign变为1

最终结果:1 - 1 + 0.5 - 0.166667 ≈ 0.333333

关键点:
  • 正确处理0! = 1
  • 使用浮点数除法(1.0/fac)
  • 每次循环改变符号(sign *= -1)
  • 阶乘通过递推计算(fac *= i)

递归方法

  • 从第0项开始
代码语言:javascript
复制
#include <stdio.h>

// 阶乘函数
double fac(int n) {
    if (n == 0 || n == 1) return 1.0;
    return n * fac(n - 1);
}

// 修正后的求和函数
double sum(int n) {
    if (n < 0) return 0.0;  // 处理非法输入

    // 第0项:1/0! = +1
    if (n == 0) return 1.0;

    // 从第1项开始,奇数项为负,偶数项为正
    double sign = (n % 2 == 1) ? -1.0 : 1.0;
    return sign / fac(n) + sum(n - 1);
}

int main() {
    int n;
    printf("请输入项数n: ");
    scanf_s("%d", &n);

    // 计算从第0项到第n-1项的和
    double result = sum(n - 1);
    printf("前%d项交替倒数阶乘和为: %.15f\n", n, result);

    return 0;
}
  • 从第一项开始
代码语言:javascript
复制
/*从第1项开始*/
#include <stdio.h>

// 阶乘函数
double fac(int n) {
    if (n == 0 || n == 1) return 1.0;
    return n * fac(n - 1);
}

// 计算从第1项开始的交替倒数阶乘和(第一项为正)
double sum(int n) {
    if (n < 1) return 0.0;  // 处理无效输入

    // 第1项:+1/1!
    if (n == 1) return 1.0 / fac(1);

    // 从第2项开始,奇数项为正,偶数项为负
    double sign = (n % 2 == 0) ? -1.0 : 1.0;
    return sign / fac(n) + sum(n - 1);
}

int main() {
    int n;
    printf("请输入项数n: ");
    scanf("%d", &n);

    // 计算从第1项到第n项的和
    double result = sum(n);
    printf("前%d项交替倒数阶乘和(+1/1! -1/2! +...): %.15f\n", n, result);

    return 0;
}
  • 优化算法(避免重复计算阶乘)
代码语言:javascript
复制
#include <stdio.h>

double optimized_alternating_sum(int n) {
    double sum = 0.0;
    double term = 1.0; // 第一项1/1!
    int sign = 1;
    
    for (int i = 1; i <= n; i++) {
        sum += sign * term;
        term /= (i + 1); // 计算下一项1/(i+1)!
        sign *= -1; // 改变符号
    }
    
    return sum;
}

int main() {
    int n;
    printf("请输入项数n: ");
    scanf("%d", &n);
    
    double result = optimized_alternating_sum(n);
    printf("前%d项交替倒数阶乘和为: %.15f\n", n, result);
    
    return 0;
}

由于我们还没研究函数递归,我们主要讲基本方法,另外两种方法也会给大家带上,方便大家后面回来复习

练习十五:计算水仙花数

本任务是输出指定数以内所有的水仙花数。 水仙花数:是 n位数且等于其各位数字的 n次方和。

注意:水仙花数至少为3位数

三位数的水仙花数(基础)

代码语言:javascript
复制
#include <stdio.h>
#include <math.h>

int main() {

	int num = 0, max = 0;
	printf("请输入范围:");
	scanf_s("%d",&max);

	int a = 0, b = 0, c = 0;

	printf("0~%d范围内的水仙花数是:");
	for (int i = 0; i <= max && i <= 999; i++) {
		a = i % 10;
		b = i / 10 % 10;
		c = i / 100;
		int sum = pow(a, 3) + pow(b, 3) + pow(c, 3);
		if (i == sum&&i >100){
			printf("%d\n", sum);
		}
	}
	return 0;
}

任意数位的水仙花数

代码语言:javascript
复制
#include <stdio.h>
#include <math.h>

int isNarcissistic(int num) {
    if (num < 100) return 0;  // 至少3位数
    int original = num;
    int sum = 0;
    int digits = (int)log10(num) + 1;  // 计算位数

    while (num > 0) {
        int digit = num % 10;
        sum += pow(digit, digits);  // 动态计算幂次
        num /= 10;
    }
    return sum == original;
}

int main() {
    int max;
    printf("请输入范围:");
    scanf("%d", &max);

    printf("0~%d范围内的水仙花数是:\n", max);
    for (int i = 100; i <= max; i++) {
        if (isNarcissistic(i)) {
            printf("%d\n", i);
        }
    }
    return 0;
}

练习十六:求圆周率的近似问题(难上加难)

这一关我会给出几种方法来求解,其中莱布尼茨的方法最简单,剩下的几种方法自己可以斟酌练习(因为小编也很头疼)

莱布尼茨级数

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
#include <stdio.h>

int main() {
    int terms = 0;//定义项数和总数并初始化
    double pi, variable = 0.0;                     //根据公式pi/4=...(我们把右边代为variable)

    scanf_s("%d", &terms);
    for (int i = 1, count = 1; count < terms;count++, i += 2) {
        //奇数项为正,偶数项为负
        int sign = (count % 2 == 1 ? 1 : -1);
        variable += sign * (1.0 / i);
    }

    pi = 4 * variable;
    printf("π ≈ %.15f (使用莱布尼茨级数,%d项)\n",
        pi, terms);
    return 0;
}
  • 关键点
  1. 因为是近似计算,为了使得计算结果会更精确,测试时输入100000000项以上
  2. for循环两个局部变量的定义
  3. 结合前面练习的阶乘运算和正负相交运算

蒙特卡洛方法

这个代码光理解起来难度就很大,建议斟酌考虑学习

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

double calculate_pi_monte_carlo(int samples) {
    int hits = 0;
    srand(time(NULL));
    for (int i = 0; i < samples; i++) {
        double x = (double)rand() / RAND_MAX;
        double y = (double)rand() / RAND_MAX;
        if (x * x + y * y <= 1.0) hits++;
    }
    return 4.0 * hits / samples;
}

int main() {
    int samples = 1000000;
    printf("π ≈ %.6f (蒙特卡洛方法,%d次采样)\n", calculate_pi_monte_carlo(samples), samples);
    return 0;
}

练习十七:母牛问题(难)

在这里插入图片描述
在这里插入图片描述

代码思路

利用if语句编写出分支函数体

代码语言:javascript
复制
#include <stdio.h>

int cow_number(int n) {
    if (n <= 3) {
        return 1;
    }
    else {
        return cow_number(n - 1) + cow_number(n - 3);
    }
}

int main() {
    int n;
    printf("请输入年份n:");
    scanf("%d", &n);
    printf("第%d年有%d头母牛\n", n, cow_number(n));
    return 0;
}

练习十八:打印九九乘法表(重点/难点)

这道关具有高难度、多样性、逻辑严密,将它放最后一道也无可厚非 但是同时它也是分支与循环的重点题目之一,需要多加练习熟练掌握

不同格式的乘法表

C语言打印九九乘法表可以直角在左上角``右上角``左下角``右下角``顶部正中央,当然,难度也逐级递增

(1)左下三角格式

设计思路: 外层循环控制行数(乘数) 内层循环控制列数(被乘数),但只循环到当前行数 这样每行输出的乘法式子数量等于行号

  1. 第一个for循环控制行数(乘数)
代码语言:javascript
复制
for (int i = 1; i <= 9; i++) 
  1. 第二个for循环控制列数(被乘数)
代码语言:javascript
复制
for (j = 1; j <= i; j++)

注意:打印完一行的列数记得换行

  1. 打印格式
代码语言:javascript
复制
printf("%d×%d=%-2d ", j, i, i*j);
拓展

  • 在乘法表场景中,%-2d是最合适的选择,因为:
  • 最大乘积是9×9=81(两位数)
  • 左对齐更符合阅读习惯
  • 固定宽度确保表格整齐
完整代码展示
代码语言:javascript
复制
#include <stdio.h>

int main() {
    int i, j;
    for (i = 1; i <= 9; i++) {
        for (j = 1; j <= i; j++) {
            printf("%d×%d=%-2d ", j, i, i*j);
        }
        printf("\n");
    }
    return 0;
}
(2)右上三角格式

设计思路: 内外层都完整循环1-9 当列数小于行数时,输出空格占位 否则输出乘法式子

  1. 第一个for循环控制行数
代码语言:javascript
复制
for (i = 1; i <= 9; i++)
  1. 第二个for循环控制列数 注意: 每一行的列数是从i~9
代码语言:javascript
复制
for (j = 1; j <= 9; j++)
  1. 打印格式 关键点:
代码语言:javascript
复制
if(j < i) printf("       ");  // 空格占位
else printf("%d×%d=%-2d ", i, j, i*j);
完整代码展示
代码语言:javascript
复制
#include <stdio.h>

int main() {
    int i, j;
    for (i = 1; i <= 9; i++) {
        for (j = 1; j <= 9; j++) {
            if (j < i) {
                printf("       ");
            } else {
                printf("%d×%d=%-2d ", i, j, i*j);
            }
        }
        printf("\n");
    }
    return 0;
}
(3)完整方形格式

这道题如果你结合前两道其实难度不大,不作过多讲解

代码语言:javascript
复制
#include <stdio.h>

int main() {
    int i, j;
    for (i = 1; i <= 9; i++) {
        for (j = 1; j <= 9; j++) {
            printf("%d×%d=%-2d ", i, j, i*j);
        }
        printf("\n");
    }
    return 0;
}
(4)左上三角格式
代码语言:javascript
复制
#include <stdio.h>

int main() {
    int i, j;
    for (i = 1; i <= 9; i++) {
        for (j = 1; j <= 10-i; j++) {
            printf("%d×%d=%-2d ", i, j, i*j);
        }
        printf("\n");
    }
    return 0;
}

注意 这道题的第二个for循环i~10-i(结合乘法表理解)

下面给出九九乘法表最难也是最美观的一种

(5)金字塔格式

难点 计算需要前面需要打印多少个空格

第1行:9-1=8组空格 第2行:9-2=7组空格 … 第9行:9-9=0组空格

设计思路

  1. 外层循环:控制行数(1到9)
  2. 前导空格循环:
  • 计算每行需要的前导空格数量:9 - i
  • 每个乘法项预留4个字符空间(如"1×1=1 "占6个字符,但为了对齐我们简化为4个
  1. 乘法表内容循环:
  • 从1到当前行号i打印乘法项
  • 使用%-2d确保乘积占2个字符宽度,左对齐
  1. 换行:每行结束后换行

格式调整技巧

  1. 若要更精确控制对齐,可以:
  • 计算每个乘法项的实际宽度(如"1×1=1 "为6字符,"3×4=12 "为7字符)
  • 使用更复杂的空格计算方式
  1. 若要改变三角形的大小:
  • 调整外层循环的终止条件
  • 相应调整前导空格的计算公式
  1. 若要改变乘法项的间隔:
  • 调整printf中的空格数量
  • 或使用\t制表符代替空格
完整代码
代码语言:javascript
复制
#include <stdio.h>

int main() {
    int i, j, k;
    
    for (i = 1; i <= 9; i++) {
        // 打印前导空格,实现居中效果
        for (k = 1; k <= 9 - i; k++) {
            printf("    "); // 每个乘法项预留4个字符空间
        }
        
        // 打印乘法表内容
        for (j = 1; j <= i; j++) {
            printf("%d×%d=%-2d  ", j, i, j * i);
        }
        
        printf("\n");
    }
    
    return 0;
}

小编总结

首先你能看到这里,坚持到这里,小编倍感荣幸能和你一起在代码的世界里面奋斗 分支与循环是是所有代码编程的重难点,所以一方面为让大家掌握透彻,另一方面小编也是在突破自己 代码的世界很精彩,希望小编能陪伴你走完C语言剩下的路程!!

如果你觉得这篇文章对你有帮助

请给个三连多多支持

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-06-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 练习一:年龄划分
  • 练习二:闰年的判断
  • 练习三:操作符运算
    • 代码1
    • 代码2
  • 练习四:打印对应的星期几
  • 进阶挑战题:
  • 练习五:在屏幕上打印 1~10 的值
  • 练习六:逆序打印这个整数的每⼀位
  • 练习七:计算1~100之间3的倍数的数字之和
  • 练习八:计算一个整数是几位数
  • 练习九:找素数(重点)
    • 优化建议
  • 接下来的练习就要开始上强度了
  • 练习十:写⼀个猜数字游戏
    • 随机数函数
      • rand
      • srand
      • time
      • 设置随机数的范围
    • 代码展示
  • 练习十一:N人求最高分和平均分
  • 完整代码展示
  • 练习十二:求奇数阶乘和
  • 练习十三:近似计算e
  • 练习十四:倒数阶乘正负交叉算法题(难)
    • 基本方法
      • 代码解析:
      • 关键点:
  • 递归方法
  • 练习十五:计算水仙花数
    • 三位数的水仙花数(基础)
    • 任意数位的水仙花数
  • 练习十六:求圆周率的近似问题(难上加难)
    • 莱布尼茨级数
    • 蒙特卡洛方法
  • 练习十七:母牛问题(难)
    • 代码思路
  • 练习十八:打印九九乘法表(重点/难点)
    • 不同格式的乘法表
      • (1)左下三角格式
      • (2)右上三角格式
      • (3)完整方形格式
      • (4)左上三角格式
    • 下面给出九九乘法表最难也是最美观的一种
      • (5)金字塔格式
  • 小编总结
  • 如果你觉得这篇文章对你有帮助
  • 请给个三连多多支持
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档