第十章 数组和指针
编程练习
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");
}
}
转载于:https://blog.51cto.com/xiongyi85/1655700