《C Prime Plus》第十章编程练习笔记

153 阅读4分钟

第十章编程练习

这一章的练习题难度不是很大,但是要记的东西很多。最重要的是关于查找最大数和最小数的那道题,简单地算法对我这个初学者来说却是怎么都自己想不出,要去找别人的答案。

10.1

include <stdio.h>

#define MONTHS 12
#define YEARS 5

int main(void) {
    const float rain[YEARS][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;
    const float (*pi)[MONTHS] = rain;
    printf("YEAR    RAINFALL   (inches)\n");
    for (year = 0, total = 0; year < YEARS; ++year) {
        for (month = 0, subtot = 0; month < MONTHS; ++month) subtot += *(*(pi + year) + month); //指针表示法,本题关键
        printf("%5d   %15.1f\n", 2010 + year, subtot);
        total += subtot;
    }
    printf("\nThe yearly average is %.1f inches.\n\n", total / YEARS);
    printf("MONTHLY AVERAGES:\n");
    printf("   Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep   Oct   Nov   Dec\n");
    for (month = 0; month < MONTHS; ++month) {
        for (year = 0, subtot = 0; year < YEARS; ++year) subtot += *(*(pi + year) + month); //指针表示法,本题关键
        printf("%4.1f   ", subtot / YEARS);
    }
    printf("\n");
    return 0;
}

10.2

#include <stdio.h>

const double source[5] = {1.1, 2.2, 3.3, 4.4, 5.5}; //本题不修改source数组得值,所以优先选择声明为const类型

void copy_arr(double [], const double [], int); //接收source数组得形参也要为const类型

void copy_ptr(double [], const double [], int);

void copy_ptrs(double [], const double [], const double *);

int main(void) {
    double a[5], b[5], c[5]; //声明三个空数组
    copy_arr(a, source, 5);
    copy_ptr(b, source, 5);
    copy_ptrs(c, source, source + 5); //最后一个实参是source数组末元素后面的那个内存地址,这个地址在C语言中是允许被存在的
    return 0;
}

void copy_arr(double ai[], const double ar[], int n) { //数组表示法,可读性强,但有时编译效率不如指针表示法
    for (int i = 0; i < n; ++i) {
        ai[i] = ar[i];
        printf("%2.2f ", ai[i]); //将打印操作内置于函数里
    }
    putchar('\n');
}

void copy_ptr(double ai[], const double ar[], int n) {
    const double *pi = ar;
    for (int i = 0; i < n; ++i, ++pi) { //这里用到题目要求的递增指针++pi
        *(ai + i) = *pi;
        printf("%2.2f ", ai[i]); //将打印操作内置于函数里
    }
    putchar('\n');
}

void copy_ptrs(double ai[], const double ar[], const double *ptr) { //const double *ptr 将迭代的终点设为数组末元素后一个地址
    double *pi2 = ai;
    for (const double *pi1 = ar; pi1 < ptr; ++pi1, ++pi2) {
        *pi2 = *pi1;
        printf("%2.2f ", *pi2); //将打印操作内置于函数里
    }
}

10.3

#include <stdio.h>

int max(const int [], int);

int main(void) {
    const int a[10] = {5, 6, 3., 67, 78, 65, 4, 3, 3, 3};
    int n;
    n = max(a, 10);
    printf("%d", n);
    return 0;
}

int max(const int ar[], int n) {
    int i, max = ar[0];
    for (i = 1; i < n; ++i) max = (max > ar[i]) ? max : ar[i]; //通过遍历来查找最大数,这是个经典的算法,但是目前还无法掌握;
    return max;
}

10.4

#include <stdio.h>

int max(const double [], int);

int main(void) {
    const double a[4] = {1.1, 2.2, 3.3, 4.4};
    int n;
    n = max(a, 4);
    printf("%d", n);
    return 0;
}

int max(const double ar[], int n) {
    int index, i;
    double max = ar[0];
    for (i = 1; i < n; ++i) { //本题的算法思路:从第一个元素开始,并让它与下一个元素比大小
        if (max < ar[i]) {
            max = ar[i]; //如果比下一个元素小,最大值更新为下一个元素,如果比下一个元素大,则保持原样。
            index = i;
        }
    }
    return index;
}

10.5

#include <stdio.h>

const double ar[4] = {1.1, 4.4, 3.3, 2.2};

double max(const double [], int n);

double min(const double [], int n);

int main(void) {
    double m, n;
    m = max(ar, 4);
    n = min(ar, 4);
    printf("Delta is %g", m - n);
    return 0;
}

double max(const double ai[], int n) {
    int i;
    double m = ai[0];
    for (i = 1; i < n; ++i) m = (m > ai[i]) ? m : ai[i];
    return m;
}

double min(const double ai[], int n) {
    int i;
    double m = ai[0];
    for (i = 1; i < n; ++i) m = (m < ai[i]) ? m : ai[i];
    return m;
}

10.6

#include <stdio.h>

void dxpx(double [], int);

int main(void) {
    double ar[4] = {2.2, 4.4, 3.3, 1.1};
    dxpx(ar, 4);
    int i = 0;
    for (i = 0; i < 4; ++i) printf("%g  ", ar[i]);
    return 0;
}

void dxpx(double ai[], int n) {
    double temp;
    int i;
    for (i = 0; i < n / 2; ++i) {
        temp = ai[i];
        ai[i] = ai[n - i - 1];
        ai[n - i - 1] = temp;
    }
}

10.7

#include <stdio.h>

void copy_arr(double ai[][2], const double aar[][2], int n);

const double ar[2][2] = {{1.1, 2.2},
                         {3.3, 4.4}};

int main(void) {
    double ai[2][2];
    copy_arr(ai, ar, 2);
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 2; ++j) printf("%g  ", ai[i][j]);
    } //打印完成拷贝后的二维数组,看是否拷贝成功;
    return 0;
}

void copy_arr(double ai[][2], const double aar[][2], int n) { //数组表示法,可读性强,但有时编译效率不如指针表示法
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) ai[i][j] = aar[i][j];
    }
}

10.8


void copy_ptrs(int [], const int [], int);

const int ar[7] = {1, 2, 3, 4, 5, 6, 7};

int main(void) {
    int ai[3];
    int *pi = ai;
    const int *ptr = ar;
    copy_ptrs(pi, ptr, 3); //实参是地址和待处理元素个数,而非数组名和数组大小。
    for (int i = 0; i < 3; ++i) printf("%d  ", *(ai + i));
    return 0;
}

void copy_ptrs(int *pi, const int *ptr, int n) { //const double *ptr 将迭代的终点设为数组末元素后一个地址
    for (int i = 0; i < n; ++i) {
        *(pi + i) = *(ptr + 2 + i); //ar+2表示为ar数组得第三个元素开始,i<n为在哪个元素结束loop;
    }
}

10.9

#include <stdio.h>

double a[3][5] = {{1.1, 2.2, 3.3, 4.4, 5.5},
                  {1.1, 2.2, 3.3, 4.4, 5.5},
                  {1.1, 2.2, 3.3, 4.4, 5.5}};

void copy_arr(int n, int m, double ai[n][m], double ar[n][m]); //变长数组的声明规则

void show_arr(int n, int m, double ai[n][m]);

int main(void) {
    double b[3][5];
    copy_arr(3, 5, b, a);
    printf("List a is :\n");
    show_arr(3, 5, a);
    printf("\nList b is :\n");
    show_arr(3, 5, b);
    return 0;
}

void copy_arr(int n, int m, double ai[n][m], double ar[n][m]) {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            ai[i][j] = ar[i][j];
        }
    }
    return;
}

void show_arr(int n, int m, double ai[n][m]) {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            printf("%g  ", ai[i][j]);
        }
    }
}

10.11

#include <stdio.h>

void fanbei_arr(int ai[][5], int n);

void show_arr(int ai[][5], int n);

int main(void) {
    int ar[3][5] = {{1, 2, 3, 4, 5},
                    {1, 2, 3, 4, 5},
                    {1, 2, 3, 4, 5}};
    show_arr(ar, 3); //函数名和行数作为参数;
    fanbei_arr(ar, 3);
    show_arr(ar, 3);
    return 0;
}

void fanbei_arr(int ai[][5], int n) {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < 5; ++j) {
            ai[i][j] *= 2;
        }
    }
}

void show_arr(int ai[][5], int n) {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < 5; ++j) {
            printf("%d  ", ai[i][j]);
        }
    }
    putchar('\n');
}

10.12

#include <stdio.h>

#define MONTHS 12
#define YEARS 5

//本质上是将二维数组作为参数传入函数,处理二维数组的数据
void total_rain(float [][12], int n);

void month_average_rain(float [][12], int n);

int main() {
    float rain[YEARS][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}
    };
    total_rain(rain, 5);
    month_average_rain(rain, 5);
    printf("\n");
    return 0;
}

void total_rain(float a[][12], int n) {
    int year, month;
    float subtot, total;
    printf("YEAR    RAINFALL   (inches)\n");
    for (year = 0, total = 0; year < n; ++year) {
        for (month = 0, subtot = 0; month < MONTHS; ++month) subtot += a[year][month];
        printf("%5d   %15.1f\n", 2010 + year, subtot);
        total += subtot;
    }
    printf("\nThe yearly average is %.1f inches.\n\n", total / YEARS);
}

void month_average_rain(float a[][12], int n) {
    int year, month;
    float subtot, total;
    printf("MONTHLY AVERAGES:\n");
    printf("   Jan    Feb   Mar   Apr   May   Jun   Jul   Aug   Sep   Oct   Nov   Dec\n");
    for (month = 0; month < MONTHS; ++month) {
        for (year = 0, subtot = 0; year < n; ++year)subtot += a[year][month];
        printf("%4.1f   ", subtot / YEARS);
    }
}

10.13

#include <stdio.h>

void in(double [][5], int n); //将用户输入的数字传入二维数组,采用传统C处理数组的方式

double average1d(double []); //对一维数组求平均值,采用传统C处理数组的方式

double average2d(double [][5], int n);//对整个二维数组求平均值,采用传统C处理数组的方式

double maxnum(double *);//直接用指针指向二维数组第一个数组的第一个元素,然后遍历所有double元素,查找最大值;

int main(void) {
    double average, max;
    double input[3][5];

    in(input, 3);
    for (int i = 0; i < 3; ++i) {
        average = average1d(input[i]);
        printf("The average of %dst list is %g\n", i, average);
    }
    average = average2d(input, 3);
    printf("The average of whole list is %g\n", average);
    double *ptr = &input[0][0];
    max = maxnum(ptr);
    printf("The max of whole list is %g\n", max);
    return 0;
}

void in(double ai[][5], int n) {
    double num;
    int m = 0;
    while (m < n) {
        for (int i = 0; i < 5; ++i) {
            scanf("%lf", &num);
            while (getchar() != '\n') continue; //将用户输入的换行符消除掉
            ai[m][i] = num;
        }
        m++;
    }
}

double average1d(double ai[]) {
    double sum = 0;
    double average;
    for (int i = 0; i < 5; ++i) {
        sum += ai[i];
    }
    average = sum / 5;
    return average;
}

double average2d(double ai[][5], int n) {
    double sum = 0;
    double average;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < 5; ++j) {
            sum += ai[i][j];
        }
    }
    average = sum / (3 * 5);
    return average;
}

double maxnum(double *pi) {
    double max = *pi;
    for (int i = 1; i < 15; ++i) {
        max = (max < *(pi + i)) ? *(pi + i) : max;
    }
    return max;
}

10.14

#include <stdio.h>

void in(int n, int m, double [n][m]); //将用户输入的数字传入二维数组,采用变长数组接收数组对象

double average1d(int n, double [n]); //对一维数组求平均值,采用变长数组接收数组对象

double average2d(int n, int m, double [n][m]);//对整个二维数组求平均值,采用变长数组接收数组对象

double maxnum(double *);//直接用指针指向二维数组第一个数组的第一个元素,然后遍历所有double元素,查找最大值;

int main(void) {
    double average, max;
    int n = 3;
    int m = 5;
    double input[n][m];
    in(n, m, input);
    for (int i = 0; i < 3; ++i) {
        average = average1d(m, input[i]);
        printf("The average of %dst list is %g\n", i, average);
    }
    average = average2d(3, 5, input);
    printf("The average of whole list is %g\n", average);
    double *ptr = &input[0][0];
    max = maxnum(ptr);
    printf("The max of whole list is %g\n", max);
    return 0;
}

void in(int n, int m, double ai[n][m]) {
    double num;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            scanf("%lf", &num);
            while (getchar() != '\n') continue; //将用户输入的换行符消除掉
            ai[i][j] = num;
        }
    }
}

double average1d(int n, double ai[n]) {
    double sum = 0;
    double average;
    for (int i = 0; i < n; ++i) {
        sum += ai[i];
    }
    average = sum / 5;
    return average;
}

double average2d(int n, int m, double ai[n][m]) {
    double sum = 0;
    double average;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            sum += ai[i][j];
        }
    }
    average = sum / (n * m); //直接用变量相乘得到二维数组的基本元素的个数
    return average;
}

double maxnum(double *pi) {
    double max = *pi;
    for (int i = 1; i < 15; ++i) {
        max = (max < *(pi + i)) ? *(pi + i) : max;
    }
    return max;
}