二维数组的本质
double matrix[3][4];
double matrix[3][4]; =>double [4] matrix[3]; 令type为double [4],所以double [4] matrix[3]为type matrix[3],这说明,matrix是一个一维数组,有3个元素;每个元素是type,即double [4]类型的。
matrix是什么?
&matrix[0][0] 这个操作的意思是取二维数组第0行,第0列(即整个二维数组的第一个元素)的首地址;
&matrix[0][0] <=> &( matrix[0][0] ) <=> &( ( matrix[0] ) [0] ) <=> &( (*(matrix + 0)) [0] )
<=> &( (*matrix) [0] ) <=> &( *((*matrix) + 0) ) <=> &( **matrix ) <=> &**matrix
<=> *matrix
上述一段推理证明&matrix[0][0]就是*matrix,下来,用一段程序证明这个结论:
#include <stdio.h>
int main() {
double matrix[3][4];
printf("%p %p\n", *matrix, &matrix[0][0]);
return 0;
}
运行结果如下:
上述结果证明:&matrix[0][0]就是*matrix。
回顾一下一维指针:
#include <stdio.h>
int main() {
double array[10];
double *p = NULL;
p = array; //p = &array[0] <=> p = &(*(array+0)) <=> p = &*array <=> p = array
printf("%p %p %p\n", p, array, &array[0]);
printf("%p %p\n", p+1, array+1); //p,array指类都是double类型
return 0;
}
运行结果如下:
结果说明,一维数组array的指类是double类型,array+1等于移动了一个指类的长度(即double,8个字节的长度)。
再看一下二维数组:
#include <stdio.h>
int main() {
double matrix[3][4]; //等价于double[4] matrix[3]
printf("%d\n", sizeof(double[4]));
printf("matrix:%p &matrix[0][0]:%p\n", matrix, &matrix[0][0]);
printf("matrix+1:%p &matrix[0][0]+1:%p\n", matrix+1, &matrix[0][0]+1); //matrix指类为double[4],matrix[0][0]为double
printf("*matrix+1:%p &matrix[0][0]+1:%p\n", *matrix+1, &matrix[0][0]+1); // &matrix[0][0]等价于 *matrix
return 0;
}
运行结果如下:
对每一个输出做出解释:第二行的输出地址相同,给我们一个假象:matrix和&matrix[0][0]是相同的,但是通过+1操作得到的输出地址表示,matrix+1移动了20h(即32个字节),&matrix[0][0]+1移动了8个字节,这是因为matrix和&matrix[0][0]的指类是不同的,matrix的指类是double[4],matrix[0][0]的指类是double。第三行的结果进一步证实了我们前面的推理,即:&matrix[0][0]就是*matrix,他们的指类都是double。
进一步讨论:
#include <stdio.h>
int main() {
double matrix[3][4];
scanf("%lf", &matrix[0][0]);
printf("matrix[0][0]:%lf\n", matrix[0][0]);
return 0;
}
上面这个程序,在dev和gcc下运行都是没有问题的。但是
#include <stdio.h>
int main() {
double matrix[3][4];
scanf("%lf", matrix);
printf("matrix:%lf\n", matrix[0][0]);
return 0;
}
这段程序在dev下运行没有问题,gcc下运行就出现了警告
这段警告的意思是说,scanf("%lf", matrix);这段程序的第一个参数是double *类型,而第二个参数是double (*)[4]类型的,进一步说明了matrix和&matrix[0][0]的指类是不同的。
double[4] matrix[3]; => double matrix[3][4];
double[4] *matrix; => double *matrix[4]; 这样的写法和上述表示不能等价,因为,[]优先与matrix结合,造成matrix与*的结合顺序发生更改,原来double[4] *matrix这样的写法强调的是*matrix的紧密结合,所以,为了与原来的写法等价,应该这样写:double (*matrix)[4]; 若忽略matrix变量名称,就出现了double(*)[4]的写法,诶,此时,我们发现,这个和刚才gcc的警告的写法一致了。
综上,对于二维数组可以得到如下的结论了:
double matrix[3][4] 二维数组名称matrix的类型是double(*)[4],其指类是double[4],因此,matrix+1会移动32B!!!
matrix和*matrix和&matrix[0][0]和&matrix的关系
一、关于matrix
matrix是二维数组名称,指类是double[4],matrix+1将移动32B。
二、关于*matrix:
*matrix <=> *(matrix) <=> *(matrix + 0) <=> matrix[0]
那么,matrix[0]、matrix[1]······matrix[n]是什么意思呢?
&matrix[0][0] <=> *matrix <=> matrix[0]
&matrix[1][0] <=> &( (matrix[1]) [0] ) <=> &*(matrix[1] + 0 ) <=> matrix[1]
······
&matrix[i][0] <=> &( (matrix[i]) [0] ) <=> &*(matrix[i] + 0 ) <=> matrix[i]
二维数组名称,引用二维数组元素的过程:
*matrix,对指针进行*运算,将产生“降阶”的效果,“*二阶指针”的类型就是“一阶指针”
matrix本身的指类是double[4],降阶后成为double,这等于说*matrix的指类就是double!!!
1、matrix[i][j] <=> (*(matrix+i))[j]
*(matrix+i)中:matrix+i将移动i * sizeof(double[4])字节空间,即跳跃i行元素!然后*对其进行降阶,使*(matrix+i)的指类成为double,即matrix[i]是指针,指向下标为i的那一行的首地址。只是,其指类已经变成了double!
2、(matrix[i])[j] <=> *( (matrix[i]) + j)
(matrix[i]) + j事实上移动了j * sizeof(double)个字节空间,即在行内移动了j个double元素空间。
上述二维数组名称matrix与其对应的指针变量,统称“行指针”。
matrix+i即表示在行间移动。
matrix[i]与其对应的指针变量,统称“列指针”。
matrix[i]+j即表示在列间移动。
三、关于&matrix[0][0]
与*matrix是一个意思,只是表示不同。
四、关于&matrix
因为matrix的类型是double [3][4],因此,&matrix的指类就是double [3][4],那么:&matrix+1就应该移动sizeof(double [3][4])个字节,即96个字节!
#include <stdio.h>
int main() {
double matrix[3][4];
printf("&matrix:%p\n&matrix+1:%p\n", &matrix, &matrix+1);
return 0;
}
运行结果如下: