指针与二维数组

二维数组的本质

    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;
}  

运行结果如下:

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值