我们知道一维数组名是常量指针,我们可以将一维数组名赋给一个指针类型再对一维数组进行相关的操作,那二维数组名又是什么?
我们这样初始化一个二维数组int A[3][3]={1,2,3,4,5,6,7,8}或者为int A[3][3]={ {1,2,3},{4,5,6},{7,8,9}};从后面一个定义我们可以看出二维数组是由两个一维数组组成的也就是说二维数组是“数组的数组”。
问题
了解了二维数组那么二维数组名又是什么呢,是不是和一维数组名一样是个一维指针呢?看下面代码:
1 #include<stdio.h> 2 void main() 3 { int i,j; 4 int A[3][3]={{0,1,2},{3,4,5},{6,7,8}}; 5 printf("%x ",A); 6 printf("%x ",*A); 7 printf("%d ",**A); 8 9 }
从代码的结果可以看出只有**A才能输出数组中的元素,*A输出的是一个地址,那么我们是不是可以吧二维数组名理解为指针的指针。然后定义一个指针的指针 int **p,将数组名赋给p然后二维数组进行相关操作呢?答案是否定的,看下面代码:
代码1
1 #include<stdio.h> 2 void main() 3 { int i,j; 4 int A[3][3]={{0,1,2},{3,4,5},{6,7,8}}; 5 int **p; 6 p=A; 7 printf("%d",**p); 8 9 }
但是这个代码编译不过,显示error为“无法从int[3][3]转化为int **,那就说明了二维数组名不是指针的指针。那二维数组名又是什么呢?看代码:
代码2
1 #include<stdio.h> 2 void main() 3 { int i,j; 4 int A[3][3]={{0,1,2},{3,4,5},{6,7,8}}; 5 int (*p)[3]; 6 p=A; 7 for(i=0;i<3;i++) 8 { for(j=0;j<3;j++) 9 printf("%2d",*(*(p+i)+j)); 10 printf(" "); 11 } 12 13 }
从这个结果我们可以看出我们可以先定义一个数组指针int (*p)[3],然后将A数组名然后进行相关操作,即二维数组名是一个数组指针,然后对P+1指向的是下一个数组即下一行的地址进行操作。
原因
二维数组名即数组地址,指向首行地址,不是指针的指针。表面上看,行地址即一维数组指针,而数组名指向行搜索就应该是指针的指针。 但是你考虑过没有,如果A[3][3],假设int**p=A; 那么要对行递增执行p++时,编译器如何知道列宽?因为int**是指指向一个 int 类型的指针,其数据宽度是4字节,内置宽度,因此p将指向下一个整数元素地址,也就是p递增了4字节,而不是3个int型数据的宽度,这就错位了。 所以A[3][3]的地址类型不是简单的指针的指针,而是行指针的指针,而行宽是由你定义的数组列数和元素类型所决定,int类型就是4*3=12个字节。这叫数据对齐。因此编译器在转换数组名时,会根据对齐要求而确定相应的指针类型,所以A的地址类型应该是int ()[3],而不是int **。 所以应该这样int (*p)[3]=A; 其含义为,p是一个指向(含3个int类型元素的一维数组或行的)指针,其实本质上任何指针都是4字节(32位系统),你完全可以将一种指针类型强制转为任何其他类型,那为什么还要区分指针类型,就是为了指针运算时实现数据对齐,准确定位。
转自:http://m.blog.csdn.net/toyalll/article/details/50043193