1.二维数组在内存中的布局
一般我们都会把二维数组看做是排列在一张表格中的一行行的一维数组,但是事实上系统是决不允许程序按照这样的方式存储数据的。单个元素的存储和引用实际上是以线性的方式排列在内存中的。
数组下标操作符在C中是内置操作符,它的规则告诉我们如何去解析int p[i]和int a[i][j],实际上编译器会将数组的下标解析为解引用(*)操作符。例如:int p[i]解析为"*(p+i)",即首地址为p的第i个元素;int a[i][j]解析为“*(*(a+i)+j)",例如在一个二维数组int a[3][4] ;中,a[i][j]在内存中的地址为a+4*i+j+1,即相对于首地址a的线性偏移为4*i+j+1。
2.行指针与列指针
#define N 4 ; // N为这个二维数组中每一行的元素书目。
二维数组的行指针类型为int (*p)[N] ;因为[]运算符的优先级比*大,所以必须要有一个括号;要不然写成 int *p[N] ;这就成了一个指针数组了,这个指针数组存储N个指向整型数据的指针。
p++操作会使p指向下一行的首地址,这是因为p是行指针,指向的是一行。我们可以用sizeof(*p)测试p指向的内容的大小:
int (*p) [3] ;
printf("%d\n" , sizeof(*p) ) ;
在32位系统,vc 6.0下运行结果为:12 。
那么我们可以知道列指针指向的内容一共是一行,一行3个int类型的数据,一共12个字节。所以p++跳跃的大小为一行就不奇怪了,因为指针的加1实质上加的是该指针指向的数据类型的大小。例如:char * p ; p+操作会使p移动一个char类型大小(2个字节)。类推可以有进一步的理解。罗嗦了。。。
那么定义的int (*p)[3] ;的p指针到底是个什么类型的指针呢?
首先从p开始,先与*结合,那么p是一个指针,再与[]结合,说明指针指向的内容是一个数组,然后与int结合,说明数组里的元素的类型是int型,所以p是一个指向元素为整型的数组的指针。
关于行指针的操作:
int a[3][3] = { 1,2,3,4,5,6,7,8,9 } ;
int (*p) [3] ; // p是一个指向有4个元素的一维数组,可以视为是一个行指针
int s = 0 ;
int i ;
int k = 0 ;
for( p = a ; p < a + 3 ; p++ )
{
for( i = 0 ; i < k ; i++ )
{
s += (*p)[i] ;
}
i = 0 ;
k++ ;
}
printf("%d\n" , s ) ;
这段代码输出的是这个3*3矩阵的下三角数据之和。自己结合以上说明体会一下。
int *q = a[0] ;
那么q就是一个列指针,这个列指针指向的元素是一个整型,q++操作会使q指针移动一个int大小的距离,也就是移动一列,故曰列指针。
int a[3][3] = { 1,2,3,4,5,6,7,8,9 } ;
int s = 0 ;
for( int * p = a[0] ; p < a[0] + 9 ; p++ )
{
s += *p ;
}
printf("%d\n" , s ) ;
这段代码执行的操作是输出这个3*3矩阵所有元素的代码之和。
|