C Primer Plus第十章编程练习

第十章编程练习

首先,第一个问题要我们去修改程序清单10.7,将数组表示法改为指针表示法。用数组表示时,计算的那一行代码如下:

subtot += rain[year][month];

下面我们分析一下如何使用指针去替换掉它,首先rain即为指针指向数组的位置,也就是首元素的位置,也就是rain【0】的位置,而rain【0】是一个指针指向二维数组的首元素的位置,也就是rain【0】【0】的位置,根据这样来说,我们可以用(rain+year)来表示一维的位置,也就是数组中的数组的位置,解引用取值得到二维的首地址,也就是说*(rain + year)与rain【year】等价,然后在* (rain + year) 的基础上加month,就得到了二维数组的位置,然后解引用去得到这个位置上的值,也就是说\*(*(rain + year)+ month)与rain[year][month]等价,也就是说上面的哪一行代码可以替换成下面的指针表示:

subtot += *(*(rain + year) + month);

所以,完整的代码以及运行结果如下:

#include <stdio.h>
#define MONTHS 12 // 一年的月份数
#define YRS 5 // 年数
int main(void){
    // 用2010-2014年的降水量数据初始化数组
    const float rain[YRS][MONTHS] = {
        {4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
        {8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3},
        {9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4},
        {7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2},
        {7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2}
    };
    int year, month;
    float subtot, total;
 
    printf(" YEAR RAINFALL (inches)\n");
    for (year = 0, total = 0; year < YRS; year++){ 
        //每一年,各月的降水量总和
        for (month = 0, subtot = 0; month < MONTHS; month++)
            subtot += *(*(rain + year) + month);
        printf("%5d %15.1f\n", 2010 + year, subtot);
        total += subtot; //五年的总降水量
    }
    printf("\nThe yearly average is %.1f inches.\n\n", total/YRS);
    printf("MONTHLY AVERAGES:\n\n");
    printf(" Jan Feb Mar Apr May Jun Jul Aug Sep Oct ");
    printf(" Nov Dec\n");
 
    for (month = 0; month < MONTHS; month++){ 
        //每个月,五年的总降水量
        for (year = 0, subtot =0; year < YRS; year++)
            subtot += *(*(rain + year) + month);
        printf("%4.1f ", subtot/YRS);
    }
    printf("\n");
    return 0;
}

在这里插入图片描述

接下来,我们来看第二题,要求使用三种形参的函数去复制一个数组,首先,我们先看一下第一个,数组表示法去作为形参的函数

void copy_arr(double target[], const double source[], int x){
    int i;
    for ( i = 0; i < x; i++){
        target[i] =  source[i];
    }
    printf("数组表示法拷贝target1[]如下:\n");
    for (int j = 0; j < x; j++){
        printf("%.3lf ",target[j]);
    }
}

这个看起来还是很明朗的,通过循环将原数组的数值赋值到目标数组上,接着,我们看第二个,指针表示法以及指针递增

void copy_ptr(double * target, const double * source, int x){
    int i;
    for ( i = 0; i < x; i++){
        *(target+i) = *(source+i);
    }
    printf("指针表示法拷贝target2[]如下:\n");
    for (int j = 0; j < x; j++){
        printf("%.3lf ",target[j]);
    }
}

将数组首元素地址作为形参传递进函数,通过循环,以此将目标数组的地址上的值赋值为指定原数组地址上的值。这里也可以用另一种形式去赋值

*target = *source;
target++;
source++;

如果使用第二种方式赋值的话,最好要将目标数组的首地址先保存一下,方便后续回显,因为自增会改变target指针指向的位置,而第一种方式不会改变这个位置。同样的,我们看一下第三种形参的函数

void copy_ptrs(double * target, const double * source, const double * end){
    double * p = target;
    while (source != end){
        *target = *source;
        target++;
        source++;
    }
    printf("指针表示法拷贝target3[]如下:\n");
    for (int i = 0; i < SIZE; i++){
        printf("%.3lf ",p[i]);
    }

}

就是看一下校验条件,是不是到了数组后面的一位,最后,我们将上面的合并起来,就得到了最终的完整代码。第二题的完整代码以及运行结果如下:

#include<stdio.h>
#define SIZE 5
void copy_arr(double target[], const double source[], int x);
void copy_ptr(double * target, const double * source, int x);
void copy_ptrs(double * target, const double * source, const double * end);
int main(void){
    double source[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
    double target1[5];
    double target2[5];
    double target3[5];
    printf("内容复制开始:\n");
    copy_arr(target1,source,SIZE);
    printf("\n");
    copy_ptr(target2,source,SIZE);
    printf("\n");
    copy_ptrs(target3,source,source+5);
    printf("\n");
    printf("复制完成!\n");
    printf("原数组source[]如下:\n");
    for (int i = 0; i < SIZE; i++){
        printf("%.3lf ",source[i]);
    }
    getchar();
    return 0;
}
void copy_arr(double target[], const double source[], int x){
    int i;
    for ( i = 0; i < x; i++){
        target[i] =  source[i];
    }
    printf("数组表示法拷贝target1[]如下:\n");
    for (int j = 0; j < x; j++){
        printf("%.3lf ",target[j]);
    }
}
void copy_ptr(double * target, const double * source, int x){
    int i;
    for ( i = 0; i < x; i++){
        *(target+i) = *(source+i);
    }
    printf("指针表示法拷贝target2[]如下:\n");
    for (int j = 0; j < x; j++){
        printf("%.3lf ",target[j]);
    }
}
void copy_ptrs(double * target, const double * source, const double * end){
    double * p = target;
    while (source != end){
        *target = *source;
        target++;
        source++;
    }
    printf("指针表示法拷贝target3[]如下:\n");
    for (int i = 0; i < SIZE; i++){
        printf("%.3lf ",p[i]);
    }

}

在这里插入图片描述

好的,接下来,我们来分析一下第三个题。编写一个比较大小的函数,返回存储在int类型数组中的最大值,首先,比较大小的话,就从数组下标为0开始以此与下一个值作比较,然后搞一个变量存储下标,将两者之间的较大值存到这个变量上面,最后输出这个下标的数组数据即可。他在这没有要求数组元素是初始化定义,还是从键盘输入,所以两者均可。上面说的两种数组数据获取方式,都做一下例子,完整代码以及运行结果如下:

#include<stdio.h>
#define SIZE 6
void bijiao(int * a);
int main(void){ 
    int arr[SIZE] = {1, 2, 3, 4, 5, 1};//初始化定义数据
    int ac[SIZE];
    printf("请输入六个整数值:\n");
    for (int i = 0; i < SIZE; i++){
        scanf("%d",&ac[i]);
    }
    bijiao(arr);
    bijiao(ac);
    printf("Done!!");
    getchar();
    return 0;
}
void bijiao(int * a){
    int r = 0;
    for (int i = 0; i < SIZE; i++){
        if (*(a+r)<=*(a+i)){
            r = i;
        }else{
            r = r;
        }    
    }
    printf("该数组中最大的值为:%d\n",*(a+r));
}

在这里插入图片描述

接着,来看一下第四题,返回double类型数组中最大值的数组下标,把上面第三题的代码修改一下即可实现,下面是完整代码以及运行结果:

#include<stdio.h>
#define SIZE 6
void bijiao(double * a);
int main(void){ 
    double arr[SIZE] = {1, 2, 3, 4, 5, 1};//初始化定义数据
    double ac[SIZE];
    printf("请输入六个数值:\n");
    for (int i = 0; i < SIZE; i++){
        scanf("%lf",&ac[i]);
    }
    bijiao(arr);
    bijiao(ac);
    printf("Done!!");
    getchar();
    return 0;
}
void bijiao(double * a){
    int r = 0;
    for (int i = 0; i < SIZE; i++){
        if (*(a+r)<=*(a+i)){
            r = i;
        }else{
            r = r;
        }    
    }
    printf("该数组中最大的值的数组下标为:%d\n",r);
}

在这里插入图片描述

接着,来看一下第五题,要求返回double类型数组中的最大值与最小值的差值,我们再在前几个问题的基础上对其进行修改即可实现这个功能。完整代码以及运行结果如下:

#include<stdio.h>
#define SIZE 6
void bijiao(double * a);
int main(void){ 
    double arr[SIZE] = {1, 2, 3, 4, 5, 1};//初始化定义数据
    double ac[SIZE];
    printf("请输入六个数值:\n");
    for (int i = 0; i < SIZE; i++){
        scanf("%lf",&ac[i]);
    }
    bijiao(arr);
    bijiao(ac);
    printf("Done!!");
    getchar();
    return 0;
}
void bijiao(double * a){
    int min = 0;//获取最小值数组下标
    int max = 0;//获取最大值数组下标
    for (int i = 0; i < SIZE; i++){
        if (*(a+max)<=*(a+i)){
            max = i;
        }else{
            max = max;
        }   
        if (*(a+min)>=*(a+i)){
            min = i;
        }else{
            min = min;
        }  
    }
    printf("该数组中最大的值为:%lf\n",*(a+max));
    printf("该数组中最小的值为:%lf\n",*(a+min));
    printf("两者的差值为:%lf\n",*(a+max)-*(a+min));
}

在这里插入图片描述

ok,接下来来看第六题,将数组中的数据进行倒序排列,循环依次比较相近的两个值,然后去交换位置即可,理论可行,我们看一下实践

#include<stdio.h>
#define SIZE 6
void bijiao(double * a);
int main(void){ 
    double arr[SIZE] = {1, 2, 3, 4, 5, 1};//初始化定义数据
    double ac[SIZE];
    printf("请输入六个数值:\n");
    for (int i = 0; i < SIZE; i++){
        scanf("%lf",&ac[i]);
    }
    bijiao(ac);
    printf("Done!!");
    getchar();
    return 0;
}
void bijiao(double * a){
    double z = 0;
    for (int i = 0; i < SIZE; i++){
        for (int j = 0; j < SIZE; j++){
            if (*(a+j)<*(a+j+1)){
                z = *(a+j);
                *(a+j) = *(a+j+1);
                *(a+j+1) = z;
            }
        }
    }
    printf("倒序操作之后的数组元素为:\n");
    for (int i = 0; i < SIZE; i++){
        printf("%.3lf ",*(a+i));
    }
    printf("\n");
}

在这里插入图片描述

接下来,我们来看第七题,拷贝二维数组的内容,我们直接用指针表示法来拷贝吧,因为使用数组表示法较为简单,然后也可以使用初始化定义数组,也可以通过键盘输入,得到的完整代码以及运行结果如下:(说明,打印拷贝数组的时候,外循环里面的换行符是后来加的,所以截图可能会不太对,因为运行之后,我看着不太舒服,又加了一个换行,不过懒得在执行一遍了)

#include<stdio.h>
#define HANG 3
#define SIZE 6
void copy_ptr(double (* target)[SIZE], const double (* source)[SIZE]);
int main(void){ 
    //初始化定义数组
    double arr[HANG][SIZE] = {{1.1, 2.2, 3.3, 4.4, 5.5, 6.6},
                              {1.2, 2.2, 3.2, 4.2, 5.2, 6.2},
                              {3.1, 3.2, 3.3, 3.4, 3.5, 3.6}
                            };
    double ac[HANG][SIZE];
    double sou[HANG][SIZE];
    printf("请输入十八个数值:\n");
    for (int i = 0; i < HANG; i++){
        for (int j = 0; j < SIZE; j++){
            scanf("%lf",&ac[i][j]);
        }
    }
    copy_ptr(sou,ac);
    printf("Done!!");
    getchar();
    return 0;
}
void copy_ptr(double (* target)[SIZE], const double (* source)[SIZE]){
    for ( int i = 0; i < HANG; i++){
        for (int j = 0; j < SIZE; j++){
            *(*(target+i)+j) = *(*(source+i)+j);
        }     
    }
    printf("指针表示法拷贝sou[]如下:\n");
    for ( int i = 0; i < HANG; i++){
        for (int j = 0; j < SIZE; j++){
            printf("%.3lf ", *(*(target+i)+j));
        }
        printf("\n");  
    }
}

在这里插入图片描述

好,接着我们再来看第八题,将原数组中的部分数据复制到目标数组中,还是用第二题的编程练习的函数,完整程序代码以及运行结果如下:

#include<stdio.h>
#define SIZE 7
void copy_ptr(double *target, double *source, int x);
int main(void){
    double source[SIZE];
    double target[3];
    printf("请输入七个数据:\n");
    for (int i = 0; i < SIZE; i++){
        scanf("%lf",&source[i]);
    }
    copy_ptr(target, source+2, 3);
    printf("DONE,BYE!!");
    return 0; 
}
void copy_ptr(double *target, double *source, int x){
    int i;
    for(i=0;i<x;i++){
        *(target + i)=*(source + i);
    }
    printf("复制过来的数组元素为:\n");
    for(i=0;i<x;i++){
        printf("%.2lf ",*(target + i));
    }
    printf("\n");
}

在这里插入图片描述

好的,接下来来看第九题,题目要求我们写两个处理变长数组的函数,一个去复制数据,一个展示数据。我们先来看一下为变长数组复制数据的函数

void copy(int rows, int cols, double arr[rows][cols], double ar[rows][cols]){
    printf("复制开始*********\n");
    for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
            ar[i][j] = arr[i][j];
        }
    }
    printf("复制结束*********\n");
}

接着,是为变长数组回显数据的函数

void show(int rows, int cols, double arr[rows][cols], double ar[rows][cols]){
    printf("原数组数据显示:\n");
    for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
            printf("%.3lf ",arr[i][j]);
        }
        printf("\n");  
    }
    printf("目标数组数据显示:\n");
    for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
            printf("%.3lf ",ar[i][j]);
        }
        printf("\n");  
    }
}

综上,将其组合起来,在合适的位置调用相应的函数,完整程序代码以及运行结果如下:

#include<stdio.h>
#define HANG 3
#define SIZE 5
void copy(int rows, int cols, double arr[rows][cols], double ar[rows][cols]);
void show(int rows, int cols, double arr[rows][cols], double ar[rows][cols]);
int main(void){ 
    //初始化定义数组
    double arr[HANG][SIZE] = {{1.1, 2.2, 3.3, 4.4, 5.5},
                              {1.2, 2.2, 3.2, 4.2, 5.2},
                              {3.1, 3.2, 3.3, 3.4, 3.5}
                            };
    double sou[HANG][SIZE];
    printf("复制开始之前,展示两数组数据\n");
    show(HANG, SIZE, arr, sou);
    copy(HANG, SIZE, arr, sou);
    printf("复制完成之后,展示两数组数据\n");
    show(HANG, SIZE, arr, sou);
    printf("Done!!");
    getchar();
    return 0;
}
void copy(int rows, int cols, double arr[rows][cols], double ar[rows][cols]){
    printf("复制开始*********\n");
    for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
            ar[i][j] = arr[i][j];
        }
    }
    printf("复制结束*********\n");
}
void show(int rows, int cols, double arr[rows][cols], double ar[rows][cols]){
    printf("原数组数据显示:\n");
    for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
            printf("%.3lf ",arr[i][j]);
        }
        printf("\n");  
    }
    printf("目标数组数据显示:\n");
    for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
            printf("%.3lf ",ar[i][j]);
        }
        printf("\n");  
    }
}

在这里插入图片描述

理论上,只要将宏定义的常量进行修改,便可以处理任意二维数组。接下来,我们来看一下第十题。要求是让我们将两个数组中的值计算求和,将得到的值放到另一个数组中。也不是很复杂,完整程序代码以及运行结果如下:

#include<stdio.h>
#define SIZE 6
void add(double * a1, double * a2, double * a3, int x);
void show(double * a, int x);
int main(void){
    double a1[SIZE] = {1, 2, 3, 4, 5, 6};
    double a2[SIZE] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6};
    double a3[SIZE];
    printf("第一个数组元素如下:\n");
    show(a1,SIZE);
    printf("第二个数组元素如下:\n");
    show(a2,SIZE);
    printf("计算开始***********\n");
    add(a1, a2, a3, SIZE);
    printf("计算结束***********\n");
    printf("计算得到的数组元素如下:\n");
    show(a3,SIZE);
    printf("DONE,BYE!!");
    return 0; 
}
void add(double * a1, double * a2, double * a3, int x){
    for (int i = 0; i < x; i++){
        *(a3+i) = *(a1+i) + *(a2+i);
    }
}
void show(double * a, int x){
    printf("该数组元素如下:\n");
    for (int i = 0; i < x; i++){
        printf("%.3lf ", *(a+i));
    }
    printf("\n");
}

在这里插入图片描述

接着,我们来看一下第十一题。题目要求将一个数组中的数据翻倍,并且将先后的值分别展示一次,结果图相较于代码少两个换行符,因为运行之后效果格式不太好看,后加的,但是没有再运行一遍,无伤大雅。完整程序代码以及运行结果如下:

#include<stdio.h>
#define ROWS 3
#define COLS 5
void add(int (* a)[COLS], int x);
void show(int (* a)[COLS], int x);
int main(void){
    int arr[ROWS][COLS] = {
        {1, 2, 3, 4, 5},
        {6, 7, 8, 9, 6},
        {11, 22, 33, 44, 55}
    };
    printf("数组元素如下:\n");
    show(arr,ROWS);
    printf("翻倍操作开始*********\n");
    add(arr,ROWS);
    printf("翻倍操作结束*********\n");
    printf("更新之后的数组元素如下:\n");
    show(arr,ROWS);
    printf("DONE,BYE!!");
    return 0; 
}
void add(int (* a)[COLS], int x){
    for (int i = 0; i < x; i++){
        for (int j = 0; j < COLS; j++){
            *(*(a+i)+j) = 2**(*(a+i)+j);
        }  
    }
}
void show(int (* a)[COLS], int x){
    printf("该数组元素如下:\n");
    for (int i = 0; i < x; i++){
        for (int j = 0; j < COLS; j++){
            printf("%d ", *(*(a+i)+j));
        }
        printf("\n");
    }
    printf("\n");
}

在这里插入图片描述

接着,来看一下第十二题。唉,又是程序清单10.7,我们回看一下,要求将main()中的任务挪用到函数中进行实现,将内容放到函数体中,然后传递合适的参数即可实现这个要求,完整程序代码以及运行结果如下:

#include <stdio.h>
#define MONTHS 12 // 一年的月份数
#define YRS 5 // 年数
void function(const float rain[][MONTHS]);
int main(void){
    // 用2010-2014年的降水量数据初始化数组
    const float rain[YRS][MONTHS] = {
        {4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
        {8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3},
        {9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4},
        {7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2},
        {7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2}
    };
    printf("计算开始**********\n");
    function(rain);
    printf("计算结束**********\n");
    return 0;
}
void function(const float rain[][MONTHS]){
    int year, month;
    float subtot, total;
 
    printf(" YEAR RAINFALL (inches)\n");
    for (year = 0, total = 0; year < YRS; year++){ 
        //每一年,各月的降水量总和
        for (month = 0, subtot = 0; month < MONTHS; month++)
            subtot += *(*(rain + year) + month);
        printf("%5d %15.1f\n", 2010 + year, subtot);
        total += subtot; //五年的总降水量
    }
    printf("\nThe yearly average is %.1f inches.\n\n", total/YRS);
    printf("MONTHLY AVERAGES:\n\n");
    printf(" Jan Feb Mar Apr May Jun Jul Aug Sep Oct ");
    printf(" Nov Dec\n");
 
    for (month = 0; month < MONTHS; month++){ 
        //每个月,五年的总降水量
        for (year = 0, subtot =0; year < YRS; year++)
            subtot += *(*(rain + year) + month);
        printf("%4.1f ", subtot/YRS);
    }
    printf("\n");
}

在这里插入图片描述

好的,接着来看一下第十三题

在这里插入图片描述

首先分析一下1都有哪些要求,一开始,让在键盘输入三组数,double类型,a要求将数据放到3乘5的数组中,b要求计算每组数据的平均值,c要求计算所有数据的平均值,d要求找到所有数据中的最大值,e要求将上面的结果都打印出来。要求每个任务都用单独的函数来处理,且如何调用这几个函数也是有要求的,任务c和d还要去将结果返回到主调函数去打印显示。

好,第一步,我们要创建一个double类型的二维数组,然后写一个获取数据,并且将数据存入到数组中的函数

void cun(double (* arr)[COLS], int x, int y){
    printf("请输入数据:\n");
    printf("输入数据开始***********\n");
    for (int i = 0; i < x; i++){
        printf("请输入第%d组数据:\n",i+1);
        for (int j = 0; j < y; j++){
            scanf("%lf",*(arr+i)+j);
        }
    }
    printf("输入数据结束***********\n");
}

上面是第一版的函数代码,如果后续调试出现问题的话,我们会对其进行修正。获取到数据之后,就要看一下任务b,要求我们编写一个计算并返回一维数组平均值的函数,然后在主调函数中循环调用其三次。

printf("计算每组数据的平均值开始*******");
    for (int i = 0; i < ROWS; i++){
        printf("第%d组数据的平均值为:\n",i+1);
        jiSuan1(*(arr+i),COLS);
    }
 printf("计算每组数据的平均值结束*******");

/*--------------分割线---------------------------*/


void jiSuan1(double * arr, int x){
    double sum = 0;
    double n;
    for (int i = 0; i < x; i++){
        sum = sum + *(arr+i);
    }
    n = sum/x;
    printf("%.2lf",n);
    printf("\n");
}

上面是第一版调用以及实现任务b的内容,接着,来看任务c,计算所有数据的平均值。

    printf("*******计算所有数据的平均值开始*******");
    c = jiSuanc(arr);
    printf("所有数据的平均值为:%,2lf\n",c);
    printf("*******计算所有数据的平均值结束*******");

/*------------分割线--------------------*/

double jiSuanc(double (*arr)[COLS] ){
    double sum = 0;
    double n;
    for (int i = 0; i < ROWS; i++){
        for (int j = 0; j < COLS; j++){
            sum = sum + *(*(arr+i)+j);
        }    
    }
    n = sum/(ROWS*COLS);
    return n;
}

第一版调用以及实现任务c的内容如上,接着来看任务d,找出所有数据中的最大值。

printf("*******计算所有数据的最大值开始*******");
    d = jiSuand(arr);
    printf("所有数据中的最大值为:%,2lf\n",d);
    printf("*******计算所有数据的最大值结束*******");


/*------------分割线--------------------*/


double jiSuand(double (*arr)[COLS]){
    double max = 0;
    double n;
    for (int i = 0; i < ROWS; i++){
        for (int j = 0; j < COLS; j++){
            if (*(*(arr+i)+j)>=max){
                max = *(*(arr+i)+j);
            }
        }    
    }
    n = max;
    return n;
}

第一版调用以及实现任务d的内容如上,接着,我们来开始调试这个程序,调试的过程其实也很关键,因为偶尔会有一些令人哭笑不得的错误出现。将编译时出现的错误修正之后,得到第一版运行结果,输入数据,存储数据没有问题,任务a完成,计算每一组的平均值没有问题,经计算,结果是对的,任务b完成,然后,任务分隔符应该加几个换行符,接着,任务c和任务d输出的值有问题

在这里插入图片描述

在这里插入图片描述

检查发现在转换说明处写成了,应该是.。修正后,再运行一次

在这里插入图片描述

OK,计算后得出各个数据都没有问题,后面几个任务也实现了,这个问题就结束了。最后的程序代码如下:

#include<stdio.h>
#define ROWS 3
#define COLS 5
void cun(double (* arr)[COLS], int x, int y);
void jiSuanb(double * arr, int x);
double jiSuanc(double (*arr)[COLS] );
double jiSuand(double (*arr)[COLS]);
int main(void){
    double arr[ROWS][COLS];
    double c,d;
    cun(arr,ROWS,COLS);
    printf("*******计算每组数据的平均值开始*******\n");
    for (int i = 0; i < ROWS; i++){
        printf("第%d组数据的平均值为:\n",i+1);
        jiSuanb(*(arr+i),COLS);
    }
    printf("*******计算每组数据的平均值结束*******\n");
    printf("*******计算所有数据的平均值开始*******\n");
    c = jiSuanc(arr);
    printf("所有数据的平均值为:%.2lf\n",c);
    printf("*******计算所有数据的平均值结束*******\n");
    printf("*******计算所有数据的最大值开始*******\n");
    d = jiSuand(arr);
    printf("所有数据中的最大值为:%.2lf\n",d);
    printf("*******计算所有数据的最大值结束*******\n");
    printf("DONE!!!");
    getchar();
    return 0;
}
void cun(double (* arr)[COLS], int x, int y){
    printf("请输入数据:\n");
    printf("*******输入数据开始***********\n");
    for (int i = 0; i < x; i++){
        printf("请输入第%d组数据:\n",i+1);
        for (int j = 0; j < y; j++){
            scanf("%lf",*(arr+i)+j);
        }
    }
    printf("*******输入数据结束***********\n");
}
void jiSuanb(double * arr, int x){
    double sum = 0;
    double n;
    for (int i = 0; i < x; i++){
        sum = sum + *(arr+i);
    }
    n = sum/x;
    printf("%.2lf",n);
    printf("\n");
}
double jiSuanc(double (*arr)[COLS] ){
    double sum = 0;
    double n;
    for (int i = 0; i < ROWS; i++){
        for (int j = 0; j < COLS; j++){
            sum = sum + *(*(arr+i)+j);
        }    
    }
    n = sum/(ROWS*COLS);
    return n;
}
double jiSuand(double (*arr)[COLS]){
    double max = 0;
    double n;
    for (int i = 0; i < ROWS; i++){
        for (int j = 0; j < COLS; j++){
            if (*(*(arr+i)+j)>=max){
                max = *(*(arr+i)+j);
            }
        }    
    }
    n = max;
    return n;
}

下面来看最后一个问题,让用变长数组作为函数形参,修改程序13。呵呵,敢问变长数组的作用到底是啥,第13题,你要是感觉数组长度不够,你直接改宏定义的维度数据修改长度不就完了,非要在函数调用的时候才说明数组的长度,也许是为了在多个c文件中仍然可以使用该函数吧。唉,将函数的形参换一下。完整程序代码以及运行结果如下:

#include<stdio.h>
#define ROWS 3
#define COLS 5
void cun(int x, int y,double arr[x][y]);
void jiSuanb(int x,double arr[x]);
double jiSuanc(int x, int y,double arr[x][y] );
double jiSuand(int x, int y,double arr[x][y]);
int main(void){
    double arr[ROWS][COLS];
    double c,d;
    cun(ROWS,COLS,arr);
    printf("*******计算每组数据的平均值开始*******\n");
    for (int i = 0; i < ROWS; i++){
        printf("第%d组数据的平均值为:\n",i+1);
        jiSuanb(COLS,*(arr+i));
    }
    printf("*******计算每组数据的平均值结束*******\n");
    printf("*******计算所有数据的平均值开始*******\n");
    c = jiSuanc(ROWS,COLS,arr);
    printf("所有数据的平均值为:%.2lf\n",c);
    printf("*******计算所有数据的平均值结束*******\n");
    printf("*******计算所有数据的最大值开始*******\n");
    d = jiSuand(ROWS,COLS,arr);
    printf("所有数据中的最大值为:%.2lf\n",d);
    printf("*******计算所有数据的最大值结束*******\n");
    printf("DONE!!!");
    getchar();
    return 0;
}
void cun(int x, int y,double arr[x][y]){
    printf("请输入数据:\n");
    printf("*******输入数据开始***********\n");
    for (int i = 0; i < x; i++){
        printf("请输入第%d组数据:\n",i+1);
        for (int j = 0; j < y; j++){
            scanf("%lf",*(arr+i)+j);
        }
    }
    printf("*******输入数据结束***********\n");
}
void jiSuanb(int x,double arr[x]){
    double sum = 0;
    double n;
    for (int i = 0; i < x; i++){
        sum = sum + *(arr+i);
    }
    n = sum/x;
    printf("%.2lf",n);
    printf("\n");
}
double jiSuanc(int x, int y,double arr[x][y] ){
    double sum = 0;
    double n;
    for (int i = 0; i < x; i++){
        for (int j = 0; j < y; j++){
            sum = sum + *(*(arr+i)+j);
        }    
    }
    n = sum/(x*y);
    return n;
}
double jiSuand(int x, int y,double arr[x][y]){
    double max = 0;
    double n;
    for (int i = 0; i < x; i++){
        for (int j = 0; j < y; j++){
            if (*(*(arr+i)+j)>=max){
                max = *(*(arr+i)+j);
            }
        }    
    }
    n = max;
    return n;
}

在这里插入图片描述

最后一个问题其实就是修改了一下每个函数的形参,变长数组的意义有可能是为了函数可以适配更多的数组,如果其他的c文件去调用这一个文件的函数,也许不需要根据宏定义去设置数组长度,直接使用函数的变长数组就可以处理理论上所有的二维数组。

好,以上就是第十章所有的编程练习,怎么说呢,不愧是指针,确实比较难理解,符合我对于他之前的印象。不过相信通过积累会对指针有更深刻的认识和了解。还望诸君共勉。

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值