#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;
}
结合上面的例子,可以总结一下:
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;
}
可以发现,二维数组的情况不太一样。
在一维数组的例子中,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;
}
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;
}
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;
}