5.7 多维数组
C 语言提供了类似于矩阵的多维数组,但实际上它们并不像指针数组使用得那样广泛
我们考虑一个日期转换的问题,把某月某日这种日期表示形式转换为某年中第几天的表示形式,反之亦然
例如,3 月 1 日是非闰年的第 60 天,是闰年的第 61 天
在这里,我们定义下列两个函数以进行日期转换:
函数 day_of_year
将某月某日的日期表示形式转换为某一年中第几天的表示形式,函数 month_day
则执行相反的转换
因为后一个函数要返回两个值,所以在函数 month_day
中,月和日这两个参数使用指针的形式
例如,下列语句:
month_day(1988, 60, &m, &d);
将把 m
的值设置为 2
,把 d
的值设置为 29
(2 月 29 日)
这些函数都要用到一张记录每月天数的表(如 “ 9 月有 30 天 ” 等)
对闰年和非闰年来说,每个月的天数不同,所以,将这些天数分别存放在一个二维数组的两行中比在计算过程中判断 2 月有多少天更容易
该数组以及执行日期转换的函数如下所示:
static char daytab[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
/* day_of_year: set day of year from month & day */
int day_of_year(int year, int month, int day)
{
int i, leap;
leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
for (i = 1; i < month; i++)
day += daytab[leap][i];
return day;
}
/* month_day: set month, day from day of year */
void month_day(int year, int yearday, int *pmonth, int *pday)
{
int i, leap;
leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
for (i = 1; yearday > daytab[leap][i]; i++)
yearday -= daytab[leap][i];
*pmonth = i;
*pday = yearday;
}
我们在前面的章节中曾讲过,逻辑表达式的算术运算值只可能是 0
(为假时)或者 1
(为真时)
因此,在本例中,可以将逻辑表达式 leap
用做数组 daytab
的下标
数组 daytab
必须在函数 day_of_year
和 month_day
的外部进行声明,这样这两个函数都可以使用该数组
这里之所以将 daytab
的元素声明为 char
类型,是为了说明在 char
类型的变量中存放较小的非字符整数也是合法的
到目前为止 daytab
是我们遇到的第一个二维数组
在 C 语言中,二维数组实际上是一种特殊的一维数组,它的每个元素也是一个一维数组
因此,数组下标应该写成 daytab[i][j] /* [row][col] */
而不能写成 daytab[i,j] /* WRONG */
除了表示方式的区别外,C 语言中二维数组的使用方式和其它语言一样
数组元素按行存储,因此,当按存储顺序访问数组时,最右边的数组下标(即列)变化得最快
数组可以用花括号括起来的初值表进行初始化,二维数组的每一行由相应的子列表进行初始化
在本例中,我们将数组 daytab
的第一列元素设置为 0
,这样,月份的值为 1 ~ 12, 而不是 0 ~ 11
由于在这里存储空间并不是主要问题,所以这种处理方式比在程序中调整数组的下标更加直观
如果将二维数组作为参数传递给函数,那么在函数的参数声明中必须指明数组的列数
数组的行数没有太大关系,因为函数调用时传递的是一个指针,它指向由行向量构成的一维数组
知道列数,就知道了这个指针指向的对象的大小,编译器就能知道移动指针的步长
在之前的例子中,传递给函数的是一个指向 13 个整型元素的一维数组
因此,如果将数组 daytab
作为参数传递给函数 f
那么 f
的声明应该写成 f(int daytab[2][13]) { ... }
或 f(int daytab[][13]) { ... }
还可以写成 f(int (*daytab)[13]) { ... }
这种声明形式表明参数是一个指针,它指向具有 13 个整型元素的一维数组
因为方括号 []
的优先级高于 *
的优先级,所以上述声明中必须使用圆括号
如果去掉圆括号,则声明变成 int *daytab[13]
这相当于声明了一个数组,该数组有 13 个元素,其中每个元素都是一个指向整型对象的指针
一般来说,除数组的第一维(下标)可以不指定大小外,其余各维都必须明确指定大小
我们将在 5.12 节中进一步讨论更复杂的声明