二维数组指针,指针数组与数组指针的区别,一看就懂

目录

一.二维数组基本概念

二.指针数组和数组指针的区别

1.数组指针

2.指针数组

3.总结

三.二维数组的首地址和数组名

四.二维数组如何运用指针?

五.代码分析,加深了解。


一.二维数组基本概念

二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有“缝隙”。以下面的二维数组 a 为例:

int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };

从概念上理解,a 的分布像一个矩阵:

但在内存中,a 的分布是一维线性的,整个数组占用一块连续的内存:

C语言中的二维数组是按行排列的,也就是先存放 a[0] 行,再存放 a[1] 行,最后存放 a[2] 行;每行中的 4 个元素也是依次存放。数组 a 为 int 类型,每个元素占用 4 个字节,整个数组共占用 4×(3×4) = 48 个字节。
C语言允许把一个二维数组分解成多个一维数组来处理。对于数组 a,它可以分解成三个一维数组,即 a[0]、a[1]、a[2],而且 C 语言规定,a[0]、a[1]、a[2]分别是这三个一维数组的数组名。每一个一维数组又包含了 4 个元素,例如 a[0] 包含 a[0][0]、a[0][1]、a[0][2]、a[0][3]。

假设数组 a 中第 0 个元素的地址为 1000,那么每个一维数组的首地址如下图所示:

二.指针数组和数组指针的区别

1.数组指针

(也称行指针)

定义 int (*p)[n];

()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n。也就是说执行p+1时,p要跨过n个整型数据的长度。

如要将二维数组赋给一指针,应这样赋值:

int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
 p=&a[0];  或者p=a    //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
 p++;       //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

2.指针数组

定义 int *p[n];

[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:

int *p[3];
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i];

这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。

3.总结

这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。

三.二维数组的首地址和数组名

二维数组 a[M][N] 的数组名 a 表示的是谁的地址?

在一维数组中,数组名表示的是数组第一个元素的地址,那么二维数组呢?二维数组就是一维数组,二维数组 a[3][4] 就是有三个元素 a[0]、a[1]、a[2] 的一维数组,所以数组 a 的第一个元素不是 a[0][0],而是 a[0],所以数组名 a 表示的不是元素 a[0][0] 的地址,而是 a[0] 的地址,即

a == &a[0]
而 a[0] 又是 a[0][0] 的地址,即:
a[0] == &a[0][0]
所以二维数组名 a 和元素 a[0][0] 的关系是:
a == &(&a[0][0])

由此可知,二维数组名 a 是地址的地址,必须两次取值才可以取出数组中存储的数据。

四.二维数组如何运用指针?

二维数组利用指针的时候,其实可以运用数组指针,也可以使用指针数组,这俩个其实是都可以用的,主要是在最初赋值时存在差别。例如下面:

int nums[2][2] = {
	{1, 2},
	{2, 3}
};


//1.数组指针
int (*p)[2] =nums;
//2.或者此时 nums[0]、和 nums[1]各为一个指针数组
int *p[2] = {nums[0], nums[1]};

第一种是数组指针: int (*p)[2]=nums;语句是定义一个指针变量,指向含2个元素的第一个一维数组。所以p并不是指的是某一个元素,而是指的是一个数组,所以我们应该把第一个数组的地址赋给*p所以在赋初值时int (*p)[2] =&nums[0];或者是int (*p)[2] =nums;同时*(p+1)指向了第二个数组,也就是nums[1];此外,nums[1][0]=*(*(p+1)+0)=*(*(p+1)=**(p+1),所以*(a+i)+j == &a[i][j],即

*(*(a+i)+j) == a[i][j]。

第一种是指针数组,int *p[2] = {nums[0], nums[1]};p是包含两个指针元素的数组,指针指向的是int型,同时两个指针分别指向nums[0][0]和nums[1][0]的地址,所以在赋初值时,int *p[2] = {nums[0], nums[1]};或者int *p[2] = {nums[0], nums[1]};int *p[2] = {&nums[0][0], &nums[1][0]};

五.代码分析,加深了解。

下面看一段代码:

#include<iostream>
using namespace std;
int main()
{
int nums[2][2] = {
	{1, 2},
	{2, 3}
};

//此时 nums[0]、和 nums[1]各为一个数组
int *p[2] = {nums[0], nums[1]};

//我们可以用指针数组 p 操作一个二维数组

printf("nums[0][0] = %d\n", *p);
printf("nums[0][0] = %d\n", **p);

//指针 + 整数形式,p+1 移动到 nums 的地址,*(p +1) = nums[1],则**(p + 1) = nums[1][0]
printf("nums[1][0] = %d\n", **(p + 1));

//先*p = nums[0],再*p + 1 = &nums[0][1],最后获取内容*(*p + 1)即为 nums[0][1]
printf("nums[0][1] = %d\n", *(*p + 1));
printf("nums[1][1] = %d\n", *(*(p + 1)+1));
return 0;
}

这是想了蛮久的,同时查看了不少资料的一些理解吧,可能有不完备或错误的地方,大家可以评论区讨论,或者@博主,我们再一起研究。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值