实验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.递归与迭代:递归方式:理解了递归的概念和实现方法。在计算组合数和汉诺塔问题中,递归函数通过不断调用自身来解决问题,将复杂问题分解为更小的子问题。但也需要注意递归的深度,避免栈溢出。

迭代方式:掌握了迭代的方法,通过循环和变量的更新来逐步计算结果。与递归相比,迭代通常更高效,尤其是在处理大规模数据时。

体会感受:

 

       在解决不同问题时,需要根据问题的特点选择合适的算法。例如,计算组合数可以使用递归或迭代方式,两种方法各有优缺点。递归方式代码简洁,但可能会导致栈溢出;迭代方式效率高,但代码相对复杂一些。在打印字符小人阵列的问题中,通过分析图形的规律,选择合适的循环结构和条件判断来实现输出。通过递归方式解决问题,让我深刻体会到了程序设计的简洁之美。递归函数能够将复杂问题分解为简单的子问题,使代码更加清晰易懂。但同时也意识到递归的局限性,如栈空间的限制和性能问题。

 

posted @ 2024-10-29 21:10  顾谢耀202383290109  阅读(1)  评论(0编辑  收藏  举报