The C Programming Language(第 2 版) 笔记 / 5 指针与数组 / 5.7 多维数组

这篇博客介绍了C语言中如何使用二维数组来处理日期转换问题。通过一个二维数组daytab存储不同月份的天数,实现了将月份和日期转换为一年中的天数,以及反过来的转换。文章强调了二维数组实际上是一维数组的数组,并展示了如何初始化、访问和在函数中传递二维数组。在日期转换函数中,利用了逻辑表达式的布尔值作为数组下标,简化了代码逻辑。
摘要由CSDN通过智能技术生成

目录、参考文献


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_yearmonth_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 节中进一步讨论更复杂的声明


目录、参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值