从头学C(49)多维数组

0

C语言提供的多维数组是类似矩阵的结构,虽然实际上用的不像指针数组那么频繁,但不能否认有时用多维数组能更直观地描述一个对象。

第五章 指针与数组 >> 5.7 多维数组

来看一个日期转换的问题。给定一个具体日期 “x年x月x日”,要计算这一天是这一年的第几天;相反的,已知某一天在某一年是第几天,要计算出这一天是几月几号。

我们用函数 day_of_year 来解决第一个问题。显然,输入参数有三个:年、月、日,返回参数只有一个:第几天。

用函数 month_day 来解决第二个问题,输入参数有两个:年、第几天,返回参数有两个:月、日。我们可以把两个返回参数用指针的方式传递回主调函数。

我们知道闰年的 2 月有 29 天,而非闰年的 2 月只有 28 天,而其他月份的天数不尽相同,所以,将每个月的天数存放在一个二维数组中(类似一张表,供函数查询),以方便循环计算。

完整的代码如下:

#include <stdio.h>

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;
}
int main()
{
        int month, day;
        printf("days of 2012-11-29: %d\n", day_of_year(2012, 11, 29));
        printf("days of 2014-11-29: %d\n", day_of_year(2014, 11, 29));
        month_day(2014, 100, &month, &day);
        printf("2014 100th day: month = %d, day = %d\n", month, day);

        return 0;
}

根据闰年的规则“四年一闰,百年不闰,四百年再闰”,使用变量 leap 来表明是否为闰年,并将 leap 作为 daytab 的下标,以对应闰年和非闰年的每月天数数组。

二维数组 daytab 实际上是一种特殊的一维数组,可以把它看成是它的每个元素也是一个一维数组(比如,daytab 中有 2 个 含 13 个 char 型元素的一维数组),因此数组的下标写法是:

daytab[i][j]/* [row][col]*/

而不能写成:

daytab[i,j]    /* Wrong!!! */

数组中的元素按行存储,可以用花括号括起来的初值表进行初始化,二维数组的每一行由相应的子列表进行初始化。从程序的第 3 ~ 6 行我们可以看出 daytab 是如何定义并被初始化的。其中第一列元素被设置为 0,是为了对应月份 1 ~ 12,而不是 0 ~ 11。(如果你想节省存储空间,当然也可以用 0 ~ 11,不过在程序中需要相应的调整数组下标和月份的对应关系)

如果将二维数组作为参数传递给函数,那么在函数的参数声明中必须指明数组的列数(数组的行数没有太大关系),因为函数调用时传递的是一个指针,它指向由行向量构成的一维数组,其中每个行向量是具有 13 个整型元素的一维数组。

因此如果将数组 daytab 作为参数传递给函数 f 时,则 f 的声明应该写成下列形式:

f(int daytab[2][13]) { ... }

或者

f(int daytab[][13]) { ... }

由于数组的行数无关紧要,因此该声明还可以写成:

f(int (*daytab)[13]) { ... }

这种形式参数表明该参数是一个指针,它指向具有13个整型元素的一维数组。其中圆括号不能省略,因为方括号 [ ] 的运算符优先级高于 * ,如果去掉圆括号,声明变成:

f(int *daytab[13]) { ... }

这种形式参数表明该参数是一个指针数组,该数组有13个元素,其中每个元素都是一个指向整型对象的指针。

一般来说,除了数组的第一维下标可以不指定大小,其余各维都必须明确指定大小。

Leave A Reply