实验3_C语言函数应用编程

一、实验目的

1. 能正确使用c语法规则定义、声明、调用函数
2. 能正确编写递归函数
3. 针对具体问题场景,能合理抽象出独立的功能模块,正确定义函数并使用,使得代码更具可读性、可维护性
4. 针对具体问题场景,能正确、合理使用全局变量和局部static变量,解决实际问题

二、实验过程
1、task1:成绩等级转换
源代码:

 1 #include <stdio.h>
 2 
 3 char score_to_grade(int score);  // 函数声明
 4 
 5 int main() {
 6     int score;
 7     char grade;
 8 
 9     while (scanf_s("%d", &score) != EOF) {
10         grade = score_to_grade(score);  // 函数调用
11         printf("分数: %d, 等级: %c\n\n", score, grade);
12     }
13 
14     return 0;
15 }
16 
17 // 函数定义
18 char score_to_grade(int score) {
19     char ans;
20 
21     switch (score / 10) {
22     case 10:
23     case 9:   ans = 'A'; break;
24     case 8:   ans = 'B'; break;
25     case 7:   ans = 'C'; break;
26     case 6:   ans = 'D'; break;
27     default:  ans = 'E';
28     }
29 
30     return ans;
31 }
task1.c

运行结果:

问题回答:

问题1:函数 score_to_grade 的功能是什么?形参类型、返回值类型是什么?

答:将输入的分数(score)转换为对应的等级(grade)。根据分数的区间,它将分数分为A,B,C,D或E等级。

形参类型:该参数为 int 类型,表示分数。返回值类型:函数返回一个 char 类型的值,表示对应分数的等级(如 'A', 'B', 'C', 'D', 或 'E')。

问题2:如果line21-28以下形式,代码存在哪些问题,请逐一指出。

1  switch(score/10) {
2  case 10:
3  case 9:   ans = "A"; 
4 case 8:   ans = "B";
5  case 7:   ans = "C";
6  case 6:   ans = "D";
7  default:  ans = 'E';
8  }
task1_insert.c

答:① 字符串和字符的类型不匹配:ans = "A"; 等行使用的双引号表示字符串类型,而字符类型应该使用单引号,例如 ans = 'A';

② 缺少 break 语句:在每个 case 后面缺少 break 语句,满足某个 case 条件后,代码会继续执行后面的所有 case ,直到遇到 break 或 switch 结束,这将导致错误的等级被赋值。例如,如果 score 是 89,程序会执行到 case 8;并给 ans 赋值为 B ,然后继续执行,最后会赋值为 E 。

2、task2:计算一个整数 n 所有数字的和

源代码:

 1 #include <stdio.h>
 2 int sum_digits(int n);  // 函数声明
 3 int main() {
 4     int n;
 5     int ans;
 6     while (printf("Enter n: "), scanf_s("%d", &n) != EOF) {
 7         ans = sum_digits(n);    // 函数调用
 8         printf("n = %d, ans = %d\n\n", n, ans);
 9     }
10     return 0;
11 } 
12 
13 // 函数定义
14 int sum_digits(int n) {
15     int ans = 0;
16     while (n != 0) {
17         ans += n % 10;
18         n /= 10;
19     }
20     return ans;
21 }
task2.c

运行结果:

问题回答:

问题1:函数sum_digits的功能是什么?

答:计算并返回一个整数 n 的所有数字的和。例如,给定 n = 123,该函数会返回 1 + 2 + 3 = 6。它通过逐位提取数字(使用 n % 10)并累加这些数字实现这个功能,直到 n 减少到 0 为止。

问题2:如果保持main代码和函数sum_digits声明不变,把函数sum_digits定义成如下实现方式,能实现同 等的效果吗? 如果不能实现同等效果,分析原因。 如果能实现同等效果,说明两种实现方式背后的算法思维区别。

1  int sum_digits(int n) {
2     if(n < 10)
3         return n;
4     
5     return sum_digits(n/10) + n%10;
6  }
task2_insert

答:能实现同等效果。第一种是迭代方式:使用 while 循环,通过逐位提取数字的方式(n % 10)来累加数字,直到 n 变为 0。 这种方式在逻辑上是通过直接操作数的每一位来处理问题,通常更容易理解,且避免了递归的调用开销。 第二种是递归方式:使用递归方法 essentially calling itself with a smaller number (i.e., n / 10) until the number is less than 10. 这种方式有助于利用递归的特性,从数学角度思考问题,将复杂问题分解为更简单的部分。 递归实现可能在某些情况下易于表达(如单一表达式),但在深度递归时可能会因栈溢出而遭遇性能问题,尤其是对于大数字。

3、task3:计算整数 x 的 n 次方
源代码:

 1 #include <stdio.h>
 2 
 3 int power(int x, int n);    // 函数声明
 4 
 5 int main() {
 6     int x, n;
 7     int ans;
 8 
 9     while (printf("Enter x and n: "), scanf_s("%d%d", &x, &n) != EOF) {
10         ans = power(x, n);  // 函数调用
11         printf("n = %d, ans = %d\n\n", n, ans);
12     }
13 
14     return 0;
15 }
16 
17 // 函数定义
18 int power(int x, int n) {
19     int t;
20 
21     if (n == 0)
22         return 1;
23     else if (n % 2)
24         return x * power(x, n - 1);
25     else {
26         t = power(x, n / 2);
27         return t * t;
28     }
29 }
task3.c

运行结果:

问题回答:

问题1: 函数power的功能是什么?

答:函数 power 的功能是计算给定整数 x 的 n 次方,即 xn。

问题2:函数power是递归函数吗?如果是,找出递归模式。写出这个递归模式对应的数学公式模型。

答:函数 power 是一个递归函数。数学公式模型:

 4、task4:打印100以内的孪生素数及其总数

源代码:

 1 #include <stdio.h>  
 2 
 3 // 函数声明  
 4 int is_prime(int n);
 5 
 6 int main() {
 7     int n;
 8     int count = 0; // 孪生素数的总数  
 9     printf("100以内的孪生素数有:\n");
10 
11     // 检查2到97的数字,判断对应的n和n+2是否为素数  
12     for (n = 2; n <= 97; n++) {
13         if (is_prime(n) && is_prime(n + 2)) {
14             printf("(%d, %d)\n", n, n + 2);
15             count++; // 计数  
16         }
17     }
18 
19     // 输出孪生素数对的总数  
20     printf("100以内的孪生素数对共有%d个。\n", count);
21     return 0;
22 }
23 
24 // 判断一个正整数n是否是素数  
25 int is_prime(int n) {
26     if (n <= 1) {
27         return 0; // 小于等于1的数字不是素数  
28     }
29     for (int i = 2; i * i <= n; i++) { // 检查到平方根  
30         if (n % i == 0) {
31             return 0; // 不是素数  
32         }
33     }
34     return 1; // 是素数  
35 }
task4.c

运行结果:

 5、task5:汉诺塔

源代码:

 1 #include <stdio.h>  
 2 
 3 void move(int n, char source, char target, char auxiliary, int* count) {
 4     if (n == 1) {
 5         // 移动一个盘子并增加移动次数  
 6         printf("1: %c --> %c\n", source, target);
 7         (*count)++;
 8     }
 9     else {
10         // 递归移动n-1个盘子  
11         move(n - 1, source, auxiliary, target, count);
12         // 移动最后一个盘子  
13         printf("%d: %c --> %c\n", n, source, target);
14         (*count)++;
15         // 递归移动n-1个盘子  
16         move(n - 1, auxiliary, target, source, count);
17     }
18 }
19 
20 int main() {
21     int n;
22     while (1) {
23         printf("请输入盘子数量 : ");
24         scanf_s("%d", &n);
25         if (n == 0) {
26             break;
27         }
28 
29         int moveCount = 0; // 初始化移动次数  
30 
31         printf("盘子数量: %d\n", n);
32         move(n, 'A', 'C', 'B', &moveCount); // 从A到C,使用B作辅助  
33         printf("一共移动了%d次。\n\n", moveCount);
34     }
35 
36     return 0;
37 }
task5.c

运行结果:

 6、task6:分别用迭代方式和递归方式编写函数计算组合数

源代码:

 1 #include <stdio.h>  
 2 
 3 int func(int n, int m);   // 函数声明  
 4 
 5 int main() {
 6     int n, m;
 7     int ans;
 8 
 9     while (scanf_s("%d%d", &n, &m) != EOF) {
10         ans = func(n, m);   // 函数调用  
11         printf("n = %d, m = %d, ans = %d\n\n", n, m, ans);
12     }
13 
14     return 0;
15 }
16 
17 // 迭代方式实现组合数计算  
18 int combination_iterative(int n, int m) {
19     if (m > n || m < 0) {
20         return 0;
21     }
22     if (m == 0 || m == n) {
23         return 1;
24     }
25 
26     int result = 1;
27 
28     // 计算 C(n, m) = n! / (m! * (n - m)!)  
29     for (int i = 0; i < m; i++) {
30         result = result * (n - i) / (i + 1);
31     }
32 
33     return result;
34 }
35 
36 // 递归方式实现组合数计算  
37 int combination_recursive(int n, int m) {
38     if (m > n || m < 0) {
39         return 0;
40     }
41     if (m == 0 || m == n) {
42         return 1;
43     }
44     // C(n, m) = C(n-1, m-1) + C(n-1, m)  
45     return combination_recursive(n - 1, m - 1) + combination_recursive(n - 1, m);
46 }
47 
48 // 主函数实现  
49 int func(int n, int m) {
50     // 可以在这里选择使用哪种实现方法  
51     // return combination_iterative(n, m);    // 使用迭代方式  
52     return combination_recursive(n, m);        // 使用递归方式  
53 }
task6.c

运行结果:

7、task7:用穷举法计算三个整数的最大公约数
源代码:

 1 #include <stdio.h>  
 2 
 3 // 函数声明  
 4 int gcd(int a, int b, int c);
 5 
 6 int main() {
 7     int a, b, c;
 8     int ans;
 9     printf("请输入三个整数 (输入 Ctrl+D 或 Ctrl+Z 结束):\n");
10     while (scanf_s("%d%d%d", &a, &b, &c) != EOF) {
11         ans = gcd(a, b, c);  // 函数调用  
12         printf("最大公约数: %d\n\n", ans);
13     }
14     return 0;
15 }
16 
17 // 函数定义  
18 int gcd(int a, int b, int c) {
19     int min_num = a;
20     if (b < min_num) min_num = b;
21     if (c < min_num) min_num = c;
22 
23     for (int i = min_num; i > 0; i--) {
24         if (a % i == 0 && b % i == 0 && c % i == 0) {
25             return i;  // 找到最大公约数后立即返回  
26         }
27     }
28     return 1;  // 如果没有找到大于1的公约数,返回1  
29 }
task7.c

运行结果:

 三、实验心得

1、双引号表示字符串类型,单引号表示字符类型。

2、写程序先搭好框架,再按照算法填入相应的代码,运行调试。

3、程序错误大致有三种:算法错误、语法错误、运行结果与预期不符。

posted @ 2025-04-09 22:47  Meredith_GISer  阅读(47)  评论(0)    收藏  举报