# NENU 程序设计基础C语言 PTA(1~5章)

这里是大一入学的一门必修,会实现最最基础的C语言内容。

# 前言

作为初学者,可以去各种平台上学习C语言的语法。

善用搜索引擎、代码论坛(CSDN、稀土掘金、stack overflow)、AI(国内的kimi、文心一言、通义千问)进行学习。

可以学习笔者的代码风格,也可以不学习,但是推荐代码里的符号,例如+-*/=的前后都加上空格。

代码换行要注意,以及括号换行也要注意,请尽量保持一种代码风格,不要出现如下这种代码:

#include<stdio.h>
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++){ printf("%d",i);}
    for(int i = n;i >= 1;i--){
        for(int j = 1;j <= i;j++)
        {if(j < i) printf("%d ",j);
        }
        printf("\n");
    }
}

注意学会看报错信息,error开头的那种,不了解就先去搜索,明白”提问的艺术“。

有些字符数组的处理需要用到头文件<string.h>,有些用到根号sqrt计算的需要用到头文件<math.h>。

# 3-1 输出倒三角图案

# 思路:

这道题我们就按照输出格式里的要求输出倒三角形就好,非常的容易~

# 代码C语言:

#include<stdio.h>
int main(){
    printf("* * * *\n * * *\n  * *\n   *");
    return 0;
}

# 3-2 计算摄氏温度

# 思路:

这里我们要创建题目里需要的变量:摄氏温度c与华氏温度f,并且都是整型 int 的数据。

然后通过公式计算,输出即可。

# 代码C语言:

#include<stdio.h>
int main(){
    int f,c;
    scanf("%d",&f);
    c=5*(f-32)/9;
    printf ("Celsius = %d",c);
    return 0;
}

# 3-3 整数四则运算

# 思路:

用变量a和b读入两个正整数,然后把加减乘除分别输出即可。【记得按格式写】

# 代码C语言:

#include<stdio.h>
int main(){
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d + %d = %d\n",a,b,a+b);
    printf("%d - %d = %d\n",a,b,a-b);
    printf("%d * %d = %d\n",a,b,a*b);
    printf("%d / %d = %d\n",a,b,a/b);
    return 0;
}

# 3-4 3个整数平均值

# 思路:

读入三个整数,然后输出平均值。

我们就直接(a+b+c)/3.0即可,因为我们最后要的是浮点数类型的数据。如果直接(a+b+c)/3,(a+b+c)是整型,3是整型,最后得到的计算结果还是整型的。比如明明(1+1+1)= 3,但是(1+1+1)/ 4 得到的结果是0,因为3/4对于整型数据来说,会变成0。

所以我们除以3.0,让数据变成 整型 / 浮点型,最后结果也会被转变成浮点型。

%f是默认输出6位小数,所以我们直接输出就行。

我们用double处理计算,比float的精度高【可以认为是准确度高一点】,可以避免一些无谓的错误。

# 代码C语言:

#include<stdio.h>
int main(){
    int a,b,c;
    double aver;
    scanf("%d%d%d",&a,&b,&c);
    aver=(a+b+c)/3.0;
    printf("aver=%f",aver);
    return 0;
}

# 3-5 输出个位数字

# 思路:

我们想要输出一个数字的个位数上的数字,有各种方法。

但是最简单的方法就是,对10进行求余。

打个比方,一个数字998244353,我们把它除以10的结果就是99824435,那余数是多少?余数就是3,也就是我们要的个位数。

所以这道题我们直接把 输入的数字 % 10 之后的数字输出就可以。

# 代码C语言:

#include<stdio.h>
int main(){
    int a;
    scanf("%d",&a);
    printf("%d",a % 10);
    return 0;
}

# 4-1 计算分段函数[1]

# 思路:

这道题目我们就分支判断x是否为0,然后正常计算就可以。

这里我们可以用float或者double来处理,都可以。 如果是float,读入用 %f ;如果是double,读入用 %lf 来处理。

下方代码以double类型为例。

# 代码C语言:

#include<stdio.h>
int main(){
    double x,y;
    scanf("%lf",&x);
    if(x!=0){
        y = 1 / x;
        printf("f(%.1f) = %.1f",x,y);
    }
    else{
        y = 0;
        printf("f(%.1f) = %.1f",x,y);
    }
    return 0;
}

# 4-2 高速公路超速处罚

# 思路:

这道题的题目看着会有点棘手,但是只要搞明白数据怎么处理,倒也简单。

根据题目的意思就是,我们读入速度和限速,然后判断速度是否 ≥超过10%的限速 或者 ≥超过50%的限速,然后对应不同的输出。

这道题我们还要注意,如果要输出百分号的话,就这样写:%%

例如输出:60%,我们可以写成 printf("60%%");

这道题我们以float为例。

# 代码C语言:

#include<stdio.h>
int main(){
    float v1,v2,p;
    scanf("%f%f",&v1,&v2);
    // p 存储我们超速了多少的百分比
    p=(v1 - v2) / v2 * 100;

    if (p>=50)
        printf("Exceed %.0f%%. License Revoked",p);
    else if (p>=10) 
        printf("Exceed %.0f%%. Ticket 200",p);
    else
        printf("OK");

    return 0;
}

# 4-3 三天打鱼两天晒网

# 思路:

这道题就是个小计算题而已,我们直接把 天数%5 即可。

这样就当于把所有的天都分成很多个5天来看,如果余数是1、2、3说明是三天打鱼,如果余数是4、0说明是两天晒网。

# 代码C语言:

#include<stdio.h>
int main(){
    int n,t;
    scanf("%d",&n);
    t = n % 5;
    if(t == 4 || t == 0) printf("Drying in day %d",n);
    else printf("Fishing in day %d",n);
    return 0;
}

# 4-4 用天平找小球

# 思路:

找到唯一的不同,我们就排除法嘛,如果ab相同,则输出c,如果ac相同,则输出b,如果bc相同,则输出a。

# 代码C语言:

#include<stdio.h>
int main(){
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    if(a == b) printf("C");
    if(c == b) printf("A");
    if(a == c) printf("B");
    return 0;
}

# 4-5 装睡

# 思路:

这道题就是一个人一个人判断,我们判断一个就输出一个。

所以我们读入了每个人的数据之后,就进入if里判断,然后如果满足就输出即可。

# 代码C语言:

#include<stdio.h>
int main(){
    char a[10];
    int n,b,c,i;
    scanf("%d",&n);
    for (i = 0;i < n;i++){
        scanf("%s%d%d",a,&b,&c);
        if( b<15 || b>20 || c<50 || c>70 ){
            printf("%s\n",a);
        } 
    }
    return 0;
}

# 5-1 求平方根序列前N项和

# 思路:

这道题注意使用double,否则精度可能不够。

这道题我们从1枚举到n,然后sqrt之后加到sum上就行。

# 代码C语言:

#include<stdio.h>
#include<math.h>
int main(){
    double sum = 0;
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++){
        sum += sqrt(1.0 * i);
    }
    printf("sum = %.2f",sum);
    return 0;
}

# 5-2 求阶乘序列前N项和

# 思路:

这道题可以用双循环或者单循环。

双循环就是,外层用一个sum存储和,内层有个循环把单个阶乘计算一次。

单循环就是,我们观察到阶乘是有递推关系的,第二个阶乘的结果等于第一个阶乘的结果 × 2,第三个阶乘的结果等于第二个阶乘的结果 × 3……第 i 个阶乘的结果等于第 i - 1 个阶乘的结果 × i。所以我们可以用temp变量每次存储最后一个阶乘的结果,然后每个循环更新一下。

# 代码C语言 双循环版:

#include<stdio.h>
int main(){
    int sum = 0;
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++){
        // temp 用来存储临时数据
        int temp = 1;
        for(int j = 1;j <= i;j++){
            temp = temp * j;
        }
        sum += temp;

    }
    printf("%d",sum);
    return 0;
}

# 代码C语言 单循环版:

#include<stdio.h>
int main(){
    int sum = 0;
    int temp = 1;
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++){
        // temp 用来存储当前阶乘算到的结果
        temp *= i;
        sum += temp;

    }
    printf("%d",sum);
    return 0;
}

# 5-3 求e的近似值

# 思路:

这道题是上面这道题的变形,直接看看代码参考吧~

# 代码C语言 双循环版:

#include<stdio.h>
int main(){
    double sum = 1;
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++){
        // temp 用来存储临时数据
        int temp = 1;
        for(int j = 1;j <= i;j++){
            temp = temp * j;
        }
        sum += 1.0 / temp;

    }
    printf("%.8f",sum);
    return 0;
}

# 代码C语言 单循环版:

#include<stdio.h>
int main(){
    double sum = 1;
    int temp = 1;
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++){
        // temp 用来存储当前阶乘算到的结果
        temp *= i;
        sum += 1.0 / temp;

    }
    printf("%.8f",sum);
    return 0;
}

# 5-4 打印菱形图案

# 思路:

这道题的基本思路就是分析,每一行有多少个空格、多少个星号。

比如看样例,n = 7,第一行有6个空格,1个星号,第二行有4个空格,3个星号,第三行有2个空格5个星号,第四行有7个星号。

这样,上半部分我们就分析完了,空格数是从n - 1开始每次 -2,星号+空格数 = n。

下半部分的分析交给读者,其实就是反过来而已。

由此,我们便可以完成这道题。

# 代码C语言:

#include<stdio.h>
int main(){
    int n;
    scanf("%d",&n);
    // 中位线位置
    int middle = (n + 1) / 2;
    // 上半部分
    for(int i = 1;i <= middle;i++){
        for(int j = 1;j <= n + 1 - 2 * i;j++){
            printf(" ");
        }
        for(int j = 1;j <= 2 * i - 1;j++){
            printf("* ");
        }
        printf("\n");
    }
    // 下半部分
    for(int i = middle + 1;i <= n;i++){
        for(int j = 1;j <= 2 * i - 1 - n;j++){
            printf(" ");
        }
        for(int j = 1;j <= 2 * n - 2 * i + 1;j++){
            printf("* ");
        }
        printf("\n");
    }
    return 0;
} 

# 5-5 猴子吃桃问题

# 思路:

这道题我们倒着想。

假设第n天只剩1个,那么n - 1天不就是有2 * (1 + 1) = 4个吗?

我们根据这样的规律,可以推出,前一天的2 * (后一天 + 1),一路推到第一天即可。

这里是n到2,而不是n到1,因为如果我们推到1的时候,算出来的其实是第0天的结果,但是我们不用算到第0天。

如果循环是n - 1到1也可以,反正循环只进行n - 1次即可。

# 代码C语言:

#include<stdio.h>
int main(){
    int n;
    scanf("%d",&n);
    int ans = 1;
    for(int i = n;i >= 2;i--){
        ans = 2 * (ans + 1);
    }
    printf("%d",ans);
    return 0;
} 

# 5-6 打印水仙花数

# 思路:

这道题我们就按题目的思路来即可,比如把个十百位都拆出来,然后判断是否符合。

当然你可以枚举个十百位的值,每个都是0 ~ 9(除了百位是1 ~ 9),然后看看是否符合。

当然,这道题其实可以偷懒,直接输出样例即可。

# 代码C语言 思路一:

#include<stdio.h>
int main(){
    for(int i = 100;i <= 999;i++){
        int ge = i % 10;
        int shi = (i % 100 - ge) / 10;
        int bai = i / 100;
        if(i == ge*ge*ge + shi*shi*shi + bai*bai*bai){
            printf("%5d",i);
        }
    }
    return 0;
} 

# 代码C语言 思路二:

#include<stdio.h>
int main(){
    for(int i = 1;i <= 9;i++){
        for(int j = 0;j <= 9;j++){
            for(int k = 0;k <= 9;k++){
                if(i * 100 + j * 10 + k == i*i*i + j*j*j + k*k*k){
                    printf("%5d",i * 100 + j * 10 + k);
                }
            }
        }
    }
    return 0;
} 

# 代码C语言 偷懒版:

#include<stdio.h>
int main(){
    printf("  153  370  371  407");
    return 0;
} 

# 5-7 求整数的位数及各位数字之和

# 思路:

这道题的思路蛮重要的,注意学习。

我们怎么统计一个数字有几位?

思路一:我们每次除以10便可以拿出一位数字,这样我们就可以每次都拿到一个数字进行处理,直到数字n变为0.

思路二:我们可以把数字看作是一个字符串1234,我们把这个字符串逐位进行处理,便可以得到结果。

注意!如果是字符串的处理,我们要用string.h头文件里的函数哦~

# 代码C语言 思路一:

#include<stdio.h>
int main(){
    int n;
    scanf("%d",&n);
    int sum = 0;
    // cnt 记录数字位数
    int cnt = 0;
    while(n){
        sum += n % 10;
        n /= 10;
        cnt++;
    }
    printf("%d %d",cnt,sum);
    return 0;
} 

# 代码C语言 思路二:

#include<stdio.h>
#include<string.h>
int main(){
    char str[100];
    scanf("%s",str);
    int sum = 0;
    // strlen 可以得到字符串长度
    int len = strlen(str);
    // 字符串从下标0的位置开始存储
    for(int i = 0;i < len;i++){
        sum += str[i] - '0';
    }
    printf("%d %d",len,sum);
    return 0;
} 

# 5-8 逆序输出数的各位数字

# 思路:

这道题我们也是两个思路,和上一道题差不多,读者自行领悟~

# 代码C语言 思路一:

#include<stdio.h>
int main(){
    int n;
    scanf("%d",&n);
    while(n){
        printf("%d",n % 10);
        n /= 10;
    }
    return 0;
} 

# 代码C语言 思路二:

#include<stdio.h>
#include<string.h>
int main(){
    char str[100];
    scanf("%s",str);
    // strlen 可以得到字符串长度
    int len = strlen(str);
    // 字符串的下标从0到len - 1
    for(int i = len - 1;i >= 0;i--){
       printf("%c",str[i]);
    }
    return 0;
} 

# 5-9 小于m的最大的10个素数

# 思路:

判断素数的办法很重要!

我们判断素数的办法就是,让当前数字与比其小的数字(比其根号还小)的数字做比,看看能不能整除,如果整除说明这个数字有因数,就不是素数,反之就是素数。

我们在2~m之间的数字逆序查找即可。

详细请看代码学习!

# 代码C语言:

#include<stdio.h>
#include<math.h>
int main(){
    int m;
    scanf("%d",&m);
    // cnt 记录我们输出的素数的数量
    int cnt = 0;
    for(int i = m - 1;i >= 2;i--){
        // 此时i就是我们要判断的数字
        // 我们开始判断是不是素数
        // 我们可以用一个变量来存储我们的判断,我们默认这个数字是素数,即flag = 1
        int flag = 1;
        for(int j = 2;j <= sqrt(i);j++){
            // 如果能被整除
            if(i % j == 0){
                // 说明这一定不是素数,我们不管
                flag = 0;
            }
        }
        // flag = 1即为素数的情况,这里可以简写成if(flag)
        if(flag == 1){
            cnt++;
            printf("%6d",i);
        }
        if(cnt >= 10) break;
    }
}