关于函数与多为数组之间的相互关系,看下面一个程序就可以很清楚的了解。
#include <stdio.h>
#define ROWS 3
#define COLS 4
void sum_rows(int ar[][COLS], int rows); //第一个形参告诉该数组的地址和数据类型,第二个形参告诉函数该数组的元素个数(数组的个数)
void sum_cols(int [][COLS], int); //省略形参名,没问题
int sum2d(int(*ar)[COLS], int rows); //另一种语法
int main(void)
{
int junk[ROWS][COLS] = {
{ 2, 4, 6, 8 },
{ 3, 5, 7, 9 },
{ 12, 10, 8, 6 }
};
sum_rows(junk, ROWS);
sum_cols(junk, ROWS);
printf("Sum of all elements = %d\n", sum2d(junk, ROWS));
return 0;
}
void sum_rows(int ar[][COLS], int rows) //每一行的和
{
int r;
int c;
int tot;
for (r = 0; r < rows; r++)
{
tot = 0;
for (c =0; c < COLS; c++)
tot += ar[r][c];
printf("row %d: sum = %d\n", r, tot);
}
}
void sum_cols(int ar[][COLS], int rows) //每一列的和
{
int r;
int c;
int tot;
for (c = 0; c < COLS; c++)
{
tot = 0;
for (r = 0; r < rows; r++)
tot += ar[r][c];
printf("col %d: sum = %d\n", c, tot);
}
}
int sum2d(int ar[][COLS], int rows) //行列总和
{
int r;
int c;
int tot = 0;
for (r = 0; r < rows; r++)
for (c = 0; c < COLS; c++)
tot += ar[r][c];
return tot;
}
运行的结果:
该程序把数组名junk(即,指向数组首元素的指针,首元素是子数组)和符号常量ROWS(代表行数3)作为参数传递给函数。每个函数都把ar视为内含数组元素(每个元素是内含4个int类型值的数组)的数组。列数内置在函数体中,但是行数靠函数传递得到。如果传入函数的行数是12,那么函数要处理的是12*4数组。因为rows是元素的个数,然而,因为每个元素都数数组,或者视为一行,rows也可以看成是行数。
注意,ar和main()中的junk都使用数组表示法。因为ar和junk的类型相同,他们都是指向内含4个int类型的数组指针。
注意,下面的声明是不正确的:
int sum2(int ar[][], int rows); //错误的声明
因为编译器会把数组表示法转换成指针表示法。例如,编译器会把ar[1]转换成ar+1.编译器对ar+1求值,要知道ar所指向的对象大小。下面的声明:
int sum2(int ar[][4], int rows); //有效声明
表示ar指向一个内含4个int类型值是数组,如果第一个方括号写上数值也可以(如本例中要写3),但是编译器会忽略该值。一般而言,我们在声明一个指向N维数组的指针时(这里的N指的是大于2维的情况),只能省略最左边方括号中的值:
int sum4d(int [][12][20][30], int rows);
因为第一个方括号只是用于表明这是一个指针,而其他的方括号则是用于描述指针所指向的数据对象的类型。下面的声明与上面的声明是等价的:
int sum4d(int (*ar)[12][20][30], int rows); //ar是一个指针
这里,ar指向一个12×20×30的int数组。