第十章 数组和指针
编程练习
1.修改程序清单10.7中的程序rain,使它不使用数组下标,而是使用指针进行计算(程序中仍然需要声明并初始化数组)。
# include <stdio.h> # define MONTHS 12 # define YEARS 5 int main(void) { //把数组初始化为2000年到2004年的降水量数据 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; //降水总量 for (year = 0, total = 0; year < YEARS; year++) { for (month = 0, subtot = 0; month < MONTHS; month++) { subtot += *(*(rain + year) + month); //(rain+year)表示行地址增加,移动范围是一个数组大小。 //*rain + year表示列地址增加,移动范围是一个int类型大小。 } printf("%d年的总降水量:%.2f\n", 2010+year, subtot); total += subtot; } printf("%d年的平均降水量:%.2lf\n", YEARS, total / YEARS); printf("5年来每个月份的平均降水量:\n" ); printf(" 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月\n"); for (month = 0; month < MONTHS; month++) { for (year = 0, total = 0; year < YEARS; year++) total += *(*(rain + year) + month); printf("%4.1f ", total / YEARS); } putchar(‘\n‘); return 0; }
2.编写一个程序,初始化一个double数组,然后把数组内容复制到另外两个数组(3个数组都需要在主程序中声明)。
制作第一份拷贝的函数使用数组符号。制作第二份拷贝的函数使用指针符号,并使用指针的增量操作。
把目标数组名和要复制的元素数目做为参数传递给函数。也就是说,如果给定了下列声明,函数调用应该如下面所示:
double source [5]={1.1, 2.2, 3.3, 4.4, 5.5};
double targetl[5];
double target2 [5];
copy_arr (source, target1, 5);
copy_ptr (source, target1,5);
#include <stdio.h> void copy_ptr(double * source, double * target, int n); void copy_arr(double source[], double target[], int n); void show(double *, int); int main(void) { double source[5] = { 1.1, 2.2, 3.3, 4.4, 5.5 }; double target1[5] = { 0 }; double target2[5] = { 0 }; copy_arr(source, target1, 2); copy_ptr(source, target2, 4); printf("source: "); show(source, 5); printf("target1: "); show(target1, 5); printf("target2: "); show(target2, 5); return 0; } void copy_ptr(double * source, double * target, int n) { int i; for (i = 0; i < n; i++) *target++ = *source++; } void copy_arr(double source[], double target[], int n) { int i; for (i = 0; i < n; i++) target[i] = source[i]; } void show(double * a, int n) { int i; for (i = 0; i < n; i++) printf("%.2lf ", a[i]); printf("\n"); }
3.编写一个函数,返回一个int数组中存储的最大数值,并在一个简单的程序中测试这个函数。
#include <stdio.h> int max(int *, int); int main(void) { int a[5] = { 2, 4, 1, 0, -3 }; printf("数组中最大的值:%d\n", max(a, 5)); return 0; } int max(int * a, int n) { int i, temp = a[0]; for (i = 1; i < n; i++) { if (temp < a[i]) temp = a[i]; } return temp; }
4.编写一个函数,返回一个double数组中存储的最大数值的索引,并在一个简单程序中测试这个函数。
#include <stdio.h> int max(double *, int); int main(void) { double a[5] = { 25.6, 41.2, 13.0, 0.5, -0.03 }; printf("数组中最大值的索引:%d\n", max(a, 5)); return 0; } int max(double * a, int n) { int i, temp = 0; for (i = 1; i < n; i++) { if (a[temp] < a[i]) { temp = i; } } return temp; }
5.编写一个函数,返回一个double数组中最大的和最小的数之间的差值,并在一个简单的程序中测试这个函数。
#include <stdio.h> double sub(const double *, int); int main(void) { double a[5] = { 25.6, 41.2, 13.0, 0.5, 0.03 }; printf("数组中最大值和最小值的差值:%.2lf\n", sub(a, 5)); return 0; } double sub(const double * a, int n) { int i, max = 0, min = 0; for (i = 1; i < n; i++) { if (a[max] < a[i]) max = i; if (a[min] > a[i]) min = i; } return a[max] - a[min]; }
6.编写一个程序,初始化一个二维double数组,并利用练习2中的任一函数来把这个数组复制到另一个二维数组(因为二维数组是数组的数组,所以可以使用处理一维数组的函数来复制数组的每个子数组)。
#include <stdio.h> void copy_ptr(double * source, double * target, int n); int main(void) { double source[2][5] = { { 25.6, 41.2, 13.0, 0.5, 0.03 }, { 12.0, 23.0, -12.0, 3.0, 0.9 } }; double target[2][5] = { 0 }; copy_ptr(source[0], target[0], 8); printf("target: "); for (int i = 0; i < 2; i++) { for (int j = 0; j < 5; j++) printf("%.2lf ", target[i][j]); } printf("\n"); return 0; } void copy_ptr(double * source, double * target, int n) { int i; for (i = 0; i < n; i++) *target++ = *source++; }
7.利用练习2中的复制函数,把一个包含7个元素的数组内第3到第5元素复制到一个包含3个元素的数组中,函数本身不需要修改,只需要选择合适的实际参数(实际参数不需要是数组名和数组大小,而只需是数组元素的地址和需要复制的元素数目)
#include <stdio.h> void copy_ptr(double * source, double * target, int n); int main(void) { double source[7] = { 25.6, 41.2, 13.0, 0.5, 0.03, 3.0, 0.9 }; double target[3] = { 0 }; copy_ptr(&source[2], target, 3); printf("target: "); for (int i = 0; i < 3; i++) printf("%.2lf ", target[i]); printf("\n"); return 0; } void copy_ptr(double * source, double * target, int n) { int i; for (i = 0; i < n; i++) *target++ = *source++; }
8.编写一个程序,初始化一个3*5的二维double数组,并利用一个基于变长数组的函数把该数组复制到别一个二维数组。还要编写一个基于变长数组的函数来显示两个数组的内容。这两个函数应该能够处理任意的N*M数组(如果没有可支持变长数组的编译器,就使用传统C中处理N*5数组的函数方法)。
#include <stdio.h> void copy_ptr(int x, int y, double source[x][y], double target[x][y]); void show(int x, int y, double source[x][y], double target[x][y]); int main(void) { double source[3][5] = { { 25.6, 41.2, 13.0, 0.5, 0.03}, { 21.0, 32.0, 10.9, 5.6, 4.2 }, { 41.2, 13.0, 0.5, 2.0, 32.1 } }; double target[3][5] = { 0 }; copy_ptr(3, 5, source, target); printf("source: \n"); show(3, 5, source, target); printf("target: \n"); show(3, 5, source, target); return 0; } /* VC2013不支持变长数组,用gcc编译可通过 */ void copy_ptr(int x, int y, double source[x][y], double target[x][y]) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 5; j++) target[i][j] = source[i][j]; } } void show(int x, int y, double source[x][y], double target[x][y]) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 5; j++) printf("%.2lf ", target[i][j]); printf("\n"); } }
9.编写一个函数,把两个数组内的相应元素相加,结果存储到第3个数组内。也就是说,如果数组l具有值2、4、5、8,数组2具有值1、0、4、6,则函数对数组3赋值为3、4、9、140函数的参数包括3个数组名和数组大小。并在一个简单的程序中测试这个函数。
#include <stdio.h> #define LEN 5 void add(const int *, const int *, int *, int); void show(int *, int); int main(void) { int array1[LEN] = { 1, 3, 6, 8, 2 }; int array2[LEN] = { 2, 4, 7, 4, 9 }; int array3[LEN] = { 0 }; add(array1,array2,array3,LEN); printf("array1: \n"); show(array1, LEN); printf("array2: \n"); show(array2, LEN); printf("array3: \n"); show(array3, LEN); return 0; } void add(const int *a1, const int *a2, int *a3, int n) { for (int i = 0; i < n; i++) a3[i] = a1[i] + a2[i]; } void show(int *a, int n) { for (int i = 0; i < n; i++) printf("%5d ", a[i]); printf("\n"); }
10.编写一个程序,声明一个3x5的数组并初始化,具体数值可以随意。程序打印出数值,然后数值翻1番,接着再次打印出新值。编写一个函数来显示数组的内容,再编写另一个函数执行翻倍功能。数组名和数组行数作为参数由程序传递给函数
#include <stdio.h> void add(int array[][5], int c); void show(int (*a)[5], int); int main(void) { int array[3][5] ={ { 1, 3, 6, 8, 2 }, { 2, 4, 7, 4, 9 }, { 3, 2, 1, 2, 3 } }; printf("array: \n"); show(array, 3); add(array, 3); printf("array: \n"); show(array, 3); return 0; } void add(int array[][5], int c) { for (int i = 0; i < c; i++) for (int j = 0; j < 5; j++) array[i][j] *= 2; } void show(int (*a)[5], int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < 5; j++) printf("%5d ", a[i][j]); printf("\n"); } }
11.重写程序清单10.7的程序rain,main()中的主要功能改为由函数来执行。(针对若干年的降水量数据,计算年降水总量、年降水平均量,以及月降水平均量)
# include <stdio.h> # define MONTHS 12 # define YEARS 5 float year_total(float a[][MONTHS], int n); //五年总降水量 float month_sub(float a[][MONTHS], int n); //每个月的平均降水量 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 } }; year_total(rain, YEARS); month_sub(rain, YEARS); return 0; } float year_total(float a[][MONTHS], int n) { int i, j; float total_y, total; for (i = 0, total = 0; i < n; i++) { for (j = 0, total_y = 0; j < MONTHS; j++) total_y += a[i][j]; printf("%d年总降水量:%.1f\n", 2010 + i, total_y); total += total_y; } printf("%d年-%d年平均降水量:%.1f\n", 2010, 2010 + i-1, total / YEARS); return total; } float month_sub(float a[][MONTHS], int n) { int i, j; float total; for (i = 0; i < MONTHS; i++) { for (j = 0, total = 0; j < n; j++) total += a[j][i]; printf("%d年-%d年 %d月的平均降水量%.1f\n", 2010, 2010+j-1, i+1, total/YEARS); } return total; }
12.编写…个程序,提示用户输入3个数集,每个数集包括5个double值。程序应当实现下列所有功能:
a.把输入信息存储到一个3x5的数组中
b.计算出每个数集(包含5个数值)的平均值
c.计算所有数值的平均数
d.找出这15个数中的最大值.
e.打印出结果
每个任务需要用一个单独的函数来实现(使用传统C处理数组的方法)。对于任务b,需要编写计算并返回一维数组平均值的函数,循环3次调用该函数来实现任务b。
对于其他任务,函数应当把整个数组做为参数,并且完成任务c和d的函数应该向它的调用函数返回答案。
#include <stdio.h> void input(double(*a)[5], int n); double sub(const double *a, int n); double sub_total(const double a[][5], int n); double max(const double a[][5], int n); void show(const double a[][5], int n); int main(void) { double array[3][5]; int i; input(array, 3); for (i = 0; i < 3; i++) printf("第%d个数集的平均值:%.2lf\n",i+1, sub(array[i], 5)); printf("所有数的平均值:%.2lf\n", sub_total(array, 3)); printf("所有数中最大的数:%.2lf\n", max(array, 5)); printf("整个数集:\n"); show(array, 3); return 0; } void input(double(*a)[5], int n) { int i, j; for (i = 0; i < n; i++) { printf("请输入第%d个数集中的5个值:", i+1); for (j = 0; j < 5; j++) scanf("%lf", &a[i][j]); } } double sub(const double *a, int n) { int i; double total = 0; for (i = 0; i < n; i++) total += a[i]; return total / n; } double sub_total(const double a[][5], int n) { int i, j; double total = 0; for (i = 0; i < n; i++) { for (j = 0; j < 5; j++) total += a[i][j]; } return total / (n * 5); } double max(const double a[][5], int n) { int i, j; double temp = a[0][0]; for (i = 0; i < n; i++) { for (j = 0; j < 5; j++) if (temp < a[i][j]) temp = a[i][j]; } return temp; } void show(const double a[][5], int n) { int i, j; double max = a[0][0]; for (i = 0; i < n; i++) { for (j = 0; j < 5; j++) printf("%.2lf ", a[i][j]); printf("\n"); } }
13.下面是两个函数原型:
void show(double ar[], int n); //n是元素数
void show2(double ar2[][3], int n); //n是行数
a,编写一个函数调用,把包含数值8、3、9和2的复合文字传递给函数shows()。
b,编写一个函数调用,把包含2行3列数值的复合文字传递给函数show2(),其中第一行为8、3、9;第二行为5、4、1。
#include <stdio.h> void show(double ar[], int n); void show2(double ar2[][3], int n); int main(void) { show((double[]){ 8, 3, 9, 2 }, 4); show2((double[][3]){ { 8, 3, 9 }, { 5, 4, 1 } }, 2); return 0; } void show(double ar[], int n) { int i; for (i = 0; i < n; i++) printf("%.2lf ", ar[i]); printf("\n"); } void show2(double ar2[][3], int n) { int i, j; for (i = 0; i < n; i++) { for (j = 0; j < 3; j++) printf("%.2lf ", ar2[i][j]); printf("\n"); } }