实验3_C语言函数应用编程
任务一:
#include <stdio.h> char score_to_grade(int score); int main() { int score; char grade; while(scanf("%d", &score) != EOF) { grade = score_to_grade(score); printf("分数: %d, 等级: %c\n\n", score, grade); } return 0; } char score_to_grade(int score) { char ans; switch(score/10) { case 10: case 9: ans = 'A'; break; case 8: ans = 'B'; break; case 7: ans = 'C'; break; case 6: ans = 'D'; break; default: ans = 'E'; } return ans; }
问题1:函数score_to_grade的功能是根据传入的整数分数score,将其转换为对应的等级字符并返回。形参类型是int,即接受一个整数参数。返回值类型是char,即返回一个字符。
问题2:有问题。问题在于当score/10的值为 9 或者 10 时,执行完ans = "A"后,没有break语句,程序会继续执行下一个case,同理对于其他的case也存在这个问题。这样会导致最终返回的等级可能不是预期的结果。例如,如果score为 95,理论上应该返回等级A,但由于没有break,程序会继续执行后续的case,直到遇到break或者整个switch语句结束,这样可能会返回B、C、D或E等错误的等级。此外,ans被定义为字符类型变量,而在修改后的代码中,给ans赋值用了双引号括起来的字符串常量,这是不匹配的类型赋值,在 C 语言中会导致编译错误。
任务2:
#include <stdio.h> int sum_digits(int n); // 函数声明 #include <stdio.h> int sum_digits(int n); // 函数声明 int main() { int n; int ans; while(printf("Enter n: "), scanf("%d", &n) != EOF) { ans = sum_digits(n); // 函数调用 printf("n = %d, ans = %d\n\n", n, ans); } return 0; } // 函数定义 int sum_digits(int n) { int ans = 0; while(n != 0) { ans += n % 10; n /= 10; } return ans; }
问题 1:函数sum_digits的功能是计算给定整数n的各位数字之和并返回。
问题 2:可以实现同等效果。
两种实现方式背后的算法思维区别如下:
(1)第一种实现方式是采用循环的算法思维。通过不断地取n的末位数字累加到ans中,然后将n除以 10 去掉末位数字,重复这个过程直到n变为 0。这种方式是一种迭代的过程,逐步处理整数的每一位数字。
(2)第二种实现方式是采用递归的算法思维。如果输入的整数n小于 10,直接返回n,因为一个一位数的各位数字之和就是它本身。如果n大于等于 10,则先递归地计算n/10的各位数字之和,再加上n的末位数字n%10。这种方式是将问题不断分解为更小的子问题,直到子问题可以直接求解,然后逐步合并子问题的解得到最终结果。
任务3:
#include <stdio.h> int power(int x, int n); // 函数声明 int main() { int x, n; int ans; while(printf("Enter x and n: "), scanf("%d%d", &x, &n) != EOF) { ans = power(x, n); // 函数调用 printf("n = %d, ans = %d\n\n", n, ans); } return 0; } // 函数定义 int power(int x, int n) { int t; if(n == 0) return 1; else if(n % 2) return x * power(x, n-1); else { t = power(x, n/2); return t*t; } }
问题 1:函数power的功能是计算整数x的n次方并返回结果。
问题 2:函数power是递归函数。递归模式为:当n为 0 时,返回 1;当n为奇数时,返回x * power(x, n - 1);当n为偶数时,先计算t = power(x, n/2),然后返回t * t。
数学公式模型为
power(x, 0)= 1;
当n为奇数时,power(x, n)= x* power(x, n -1);
当n为偶数时,power(x, n)= power(x, n/2)* power(x, n/2)。
任务4:
#include <stdio.h> int is_prime(int n) { if (n <= 1) return 0; for (int i = 2; i * i <= n; i++) { if (n % i == 0) return 0; } return 1; } int main() { int count = 0; printf("100 以内的孪生素数:\n"); for (int i = 1; i < 100; i++) { if (is_prime(i) && is_prime(i + 2)) { printf("%d %d\n", i, i + 2); count++; } } printf("100 以内的孪生素数共有 %d 个\n", count); return 0; }
任务5:
#include <stdio.h> #include <stdlib.h> void hanoi(unsigned int n, char from, char temp, char to, int *count); void moveplate(unsigned int n, char from, char to, int *count); int main() { unsigned int n; while (scanf("%u", &n)!= EOF) { int count = 0; hanoi(n, 'A', 'B', 'C', &count); printf("一共移动了%d次。\n", count); } system("pause"); return 0; } void hanoi(unsigned int n, char from, char temp, char to, int *count) { if (n == 1) { moveplate(n, from, to, count); } else { hanoi(n - 1, from, to, temp, count); moveplate(n, from, to, count); hanoi(n - 1, temp, from, to, count); } } void moveplate(unsigned int n, char from, char to, int *count) { printf("%u:%c-->%c\n", n, from, to); (*count)++; }
任务6:
迭代
#include <stdio.h> int func_iterative(int n, int m) { if (m > n || m < 0) return 0; if (m == 0 || m == n) return 1; int result = 1; for (int i = 1; i <= m; i++) { result = result * (n - (m - i)) / i; } return result; } int main() { int n, m; int ans; while (scanf("%d%d", &n, &m)!= EOF) { ans = func_iterative(n, m); printf("n = %d, m = %d, ans = %d\n\n", n, m, ans); } return 0; }
递归
#include <stdio.h> int func_recursive(int n, int m) { if (m > n || m < 0) return 0; if (m == 0 || m == n) return 1; return func_recursive(n - 1, m - 1) + func_recursive(n - 1, m); } int main() { int n, m; int ans; while (scanf("%d%d", &n, &m)!= EOF) { ans = func_recursive(n, m); printf("n = %d, m = %d, ans = %d\n\n", n, m, ans); } return 0; }#include <stdio.h> #include <stdlib.h> int print_charman(int n); int main() { int n; printf("Enter n: "); scanf("%d", &n); print_charman(n); return 0; }
任务7:
int print_charman(int n){ for(int t=0;t<n;t++){ int i=(n-t)*2-1; int j=t; for(j;j>0;j--){ printf(" "); } for(i;i>0;i--){ printf(" O "); } printf("\n"); j=t; for(j;j>0;j--){ printf(" "); } i=(n-t)*2-1; for(i;i>0;i--){ printf("<H> "); } printf("\n"); j=t; for(j;j>0;j--){ printf(" "); } i=(n-t)*2-1; for(i;i>0;i--){ printf("I I "); } printf("\n"); } return 0; }
实验总结
知识归纳:
1.函数声明与定义:我学会了如何正确地声明和定义函数,明确函数的输入参数类型和返回值类型,确保在主函数中能够正确调用。理解了函数声明是为了让编译器提前知道函数的存在,而函数定义则是具体实现函数功能的代码部分。
2.循环结构:for
循环和while
循环的灵活运用。在打印字符小人阵列的程序中,使用for
循环控制行数和列数,精确地输出特定格式的图形。通过循环的条件判断,如循环变量的起始值、终止值和步长的设置,实现不同的输出效果。
3.递归与迭代:递归方式:理解了递归的概念和实现方法。在计算组合数和汉诺塔问题中,递归函数通过不断调用自身来解决问题,将复杂问题分解为更小的子问题。但也需要注意递归的深度,避免栈溢出。
迭代方式:掌握了迭代的方法,通过循环和变量的更新来逐步计算结果。与递归相比,迭代通常更高效,尤其是在处理大规模数据时。
体会感受:
在解决不同问题时,需要根据问题的特点选择合适的算法。例如,计算组合数可以使用递归或迭代方式,两种方法各有优缺点。递归方式代码简洁,但可能会导致栈溢出;迭代方式效率高,但代码相对复杂一些。在打印字符小人阵列的问题中,通过分析图形的规律,选择合适的循环结构和条件判断来实现输出。通过递归方式解决问题,让我深刻体会到了程序设计的简洁之美。递归函数能够将复杂问题分解为简单的子问题,使代码更加清晰易懂。但同时也意识到递归的局限性,如栈空间的限制和性能问题。