#P2114. 二维数组和指针

二维数组和指针

1. 复习:一维数组和指针

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int x[4];
	
	for(int i=0;i<4;i++)
			x[i] = 10+i;
	
	for(int i=0;i<4;i++)
			printf("x[%d]=%d ,它的内存地址是:%d\n",i,x[i],&x[i]);

	printf("\n");
	
	printf("\n");
	for(int i=0;i<4;i++){
		printf("x+%d=%d\n",i,x+i);
	}

	printf("\n通过地址访问数据\n");
	
	int *p;
	p = x;
	for(int i=0;i<4;i++){
		printf("*(p+%d)=%d\n",i,*(p+i)); // 不用 p 改用 x 也行的,例如 *(x+i) 
	}

	return 0;
}

img

结合上面的例子,可以总结一下:

1、 定义了一位数组 int x[4] 之后,直接引用 x ,它相当于 x[0] 的地址,x+1 相当于 x[1] 的地址。

2、可以通过 * 操作访问特定内存的变量的值

2. 二维数组和指针

一维数组的这些结论放在二维数组上是不是也一样呢?我们不妨用下面的程序来验证一下。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int x[4][3];
	
	for(int i=0;i<4;i++)
		for(int j=0;j<3;j++)
			x[i][j] = 100+i*10+j;
	
	for(int i=0;i<4;i++)
	{
		for(int j=0;j<3;j++){
			printf("x[%d][%d]=%d ,它的内存地址是:%d\n",i,j,x[i][j],&x[i][j]);
		}
		
		printf("\n");
	}

	printf("\n");
	for(int i=0;i<4;i++){
		printf("x+%d=%d\n",i,x+i);
	}

	return 0;
}

img

可以发现,二维数组的情况不太一样。

在一维数组的例子中,int x[4]; 之后,x 的值就是 x[0] 的地址,x+1 就是 x[1] 的地址....

在二维数组的例子中,int x[4][3]; 之后,x 的值是 x[0][0] 的地址,x+1 是 x[1][0] 的地址。而 x[0][0] 和 x[1][0] 在内存中的位置并不是挨在一起的,它们中间还隔着 x[0][1] 和 x[0][1]。

基于上面的这个情况,我们换一个思维去理解这个事,我们希望基于这个思维,能把一维数组的情况和二维数组的情况用同一套理论来解释。

首先,二维数组是一维数组的数组。也就是是说,有一个一维数组,是 {x[0][0],x[0][1],x[0][2]},第二个一维数组是 {x[1][0],x[1][1],x[1][2]} , 第三个一维数组是 {x[2][0],x[2][1],x[2][2]} 。这三个一维数组合在一起,构成了一维数组的数组,构成了二维数组 x 。

因为二维数组 x 是一维数组的数组,它的每一个数组元素就是一个一维数组,x+0 指向的是它的第一个数组元素的地址,x+1 指向的是第二个数组元素的地址,x+2 指向的是第三个数组元素的地址。因为数组的第二维的 size 是 3,所以,可以看到 x+1 比 x 大了 4*3 (每个 int 是 4 Byte)。所以,我们发现一维数组和二维数组的情况就可以统一起来解释了。

3. 通过指针应用二维数组的元素

3.1 通过 int 指针访问数组元素

通过指针引用一维数组元素的方法我们已经学习过了

int x[4],a,b;
int *p;
p = x;

a = *(p+1); // 相当于 a = x[1];
b = *(x+2); // 相当于 b = x[2];

类似,我们可以定义 int 指针,然后自己计算数组元素的偏移量来引用二维数组的元素。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int x[4][3];
	
	for(int i=0;i<4;i++)
		for(int j=0;j<3;j++)
			x[i][j] = 100+i*10+j;
		
	int *p;
	p = &x[0][0];

	for(int i=0;i<4;i++)
		for(int j=0;j<3;j++)		
			printf("*(p+%d*3+%d)=%d ------ x[%d][%d]=%d\n",i,j,*(p+i*3+j),i,j,x[i][j]); 

	return 0;
}

img

3.2 通过二维数组(指针)引用数组元素

上面这个方法不是太好,因为要自己来算偏移量。其实,c++ 是有语法特性帮我们简化这个事情的。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int x[4][3];
	
	for(int i=0;i<4;i++)
		for(int j=0;j<3;j++)
			x[i][j] = 100+i*10+j;

	for(int i=0;i<4;i++)
		for(int j=0;j<3;j++)
			printf("*(*(x+%d)+%d)=%d ------ x[%d][%d]=%d\n",i,j,*(*(x+i)+j),i,j,x[i][j]); 

	return 0;
}

img

x 是二维数组,是一维数组的数组,x[0] 指向一个一维数组,x[i] 指向第 i 个一维数组,*(x+i) 获得的就是第 i 个一维数组,*(x+i)+j 代表的是第 i 个一维数组里第 j 个元素的地址,再用一次 * 操作,就是拿到它的值了, *(*(x+i)+j) 就是引用 x[i][j] 。这是很重要的考点,常考。

3.3 自定义数组指针

上面的例子中我们是用 x 来引用二维数组的元素的。我们能否自己定义一个指针变量来取代 x 呢?答案是可以的,但是这个指针是数组指针。大家要注意,数组指针和指针数组是两个东西。

指针数组:一个数组,每一个数据元素都是指针。

//指针数组,数组内每一个元素都是一个指针
int *p[3];
int a=3;
int b=15;
int c=21;
p[0] = &a; // p[0] 是 int 指针,指向 a
p[1] = &b; // p[1] 是 int 指针,指向 b
p[2] = &c; // p[2] 是 int 指针,指向 c

数组指针:一个指针,是指向数组的。

//数组指针,指向一个数组的指针
int x[4][3];
int (*p)[3]; // 定义 指针变量 p,p 指向的是一个包含 3 个 int 元素的一维数组
p = x; // p 指向 x 的第 1 个一维数组
p = x+1 // p 指向 x 的第 2 个一维数组

所以,整个程序是这样写:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int x[4][3];

	for(int i=0;i<4;i++)
		for(int j=0;j<3;j++)
			x[i][j] = 100+i*10+j;

	int (*p)[3];
	p = x;

	for(int i=0;i<4;i++)
		for(int j=0;j<3;j++)
			printf("*(*(p+%d)+%d)=%d ------ x[%d][%d]=%d\n",i,j,*(*(p+i)+j),i,j,x[i][j]);

	return 0;
}

img