在刷leetcode时有道关于二维数组的题目,由于工作中较少写这块代码,对部分基础理解不足,现将学习C程序设计语言一书中关于二维数组的内容进行总结。
书中以一个日期转换函数为被背景问题,针对闰年与非闰年,可以写出二维数组的形式:
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}};
关于上述数组有几点需要解释:
首先将数组元素声明为char类型,每月天数最大值在127以内,因此可以使用char类型。
第一个元素为0,是为了跟实际月份进行对应。
用static修饰数组则表示该数组无需修改,因为对应月份所含天数固定。
/*求某年某月某日对应的天数为一年中第几天*/
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;
}
二维数组的一般形式daytab[i][j],数组元素按行存储,因此,当按存储顺序访问数组时,最右边的数组小标变化得最快。
实际上并不存在多维数组,所谓的多维数组本质上是用一维数组模拟的。数组与指针的关系是因为数组下标操作符[],比如元素a[2][1]相当于*(*(a+2)+1) 。
如果将二维数组作为参数传递给函数,那么函数的参数声明中必须指明数组的列数。数组的行数没有太大关系,函数调用时传递的是一个指针,它指向由行向量构成的一维数组,其中每个行向量是具有13个整型元素的一维数组,在该例子中,传递给函数的是一个指向很多对象的指针,其中每个对象是由13个整型元素构成的一维数组。因此,如果将数组daytab作为参数传递给函数f,那么f的声明应该写成如下形式:
f(int daytab[2][13]){……}
也可以写成
f(int daytab[][13]){……}
由于数组的行数无关紧要,所以该声明还可以写成:
f(int (*daytab)[13]){……}
这种声明形式表明参数是一个指针,它指向具有13个整型元素的一维数组。因为方括号[]的优先级高于*的优先级,所以上述声明中必须使用圆括号,如果去掉圆括号
int *daytab[13]
则变成声明一个数组,该数组有13个元素,其中每个元素都是一个指向整型对象的指针。一般来说,除数组的第一维可以不指定大小外,其余各维必须明确指定大小。
针对上面的理论知识可以参考下面的几个例子:
示例1
#include <stdio.h>
int main(int argc,char** argv)
{
int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};
printf("%d\n",a[2][1]);
printf("%d\n",a[1][4]);
return 0;
}
总结:
上面的例子中的代码在xcode中有如下告警:
Array index 4 is past the end of the array (which contains 3 elements)
针对3x3数组,下标应该在0 1 2三者之间,由于这种分配是在栈上进行的,数组的特性能够保证所有元素的地址空间连续。
示例2
#include <stdio.h>
#include <stdlib.h>
void printarry(int **a,int m,int n)
{
for(int i = 0;i < m;i++)
{
for(int j = 0;j < n;j++)
printf("%d ",a[i][j]);
printf("\n");
}
}
int main(int argc,char** argv)
{
int arr[3] ={1,2,3};
int fun[3] ={4,5,6};
int foo[3] ={7,8,9};
int *a[3] = {arr,fun,foo};
/*二维数组指针形式*/
printarry(a,3,3);
printf("%p %p %p\n",&a[0],&a[1],&a[2]);
printf("%p %p %p\n",a[0],a[1],a[2]);
printf("%p %p %p\n",arr,fun,foo);
return 0;
}
程序执行结果:
1 2 3
4 5 6
7 8 9
0x7fff5ab30500 0x7fff5ab30508 0x7fff5ab30510
0x7fff5ab30540 0x7fff5ab30530 0x7fff5ab30520
0x7fff5ab30540 0x7fff5ab30530 0x7fff5ab30520
上面例子中采用了指针数组这种形式,数组中的每个元素都是指针,由于数组arr和fun地址不连续,因此不能采用示例1中的“越界”下标形式进行访问,例如针对3x3二维数组,数组下标只能为0 1 2中的一个。
变长数组形式参数
由于C99支持变长数组,因此如下形式是正确的。
int sum_array(int n,int a[n])
需要注意的是函数参数中int n必须在int a[n]前面。
非常不错,学习了