栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

二维数组名究竟是什么?如何用指针表示二维数组里的元素?指针与数组,C语言中那些不为人知的故事,为你展开。

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

二维数组名究竟是什么?如何用指针表示二维数组里的元素?指针与数组,C语言中那些不为人知的故事,为你展开。

这里先讲一维数组:

int a[5];

int * p=&a; / /把一维数组的第一个元素的地址赋给指针p,int *是声明一个指向int类型的指针,比如数组元素是int类型,那么指针指向的就是元素,也就是int类型(记住: 指针变量存放的是地址,不是值,*p是地址)

----error---*p=a; / /不能单独这样写一行,会报错,但是这里写作int *p=a; 也对,因为a数组名代表的是数组首地址,也就是&a,它也表示数组的第一个元素的地址。

/ /赋予指针地址有两种写法,例如:

int a;
int* p = &a;

上面的代码也可以写成:

int a;
int* p;
p = &a;

p是指向整型的指针,而一维数组的第一个元素的地址赋给了指针p,所以p现在存放了这个地址,所以对p取值得到的就是数组a的第一个元素的地址,也就是数组名a,

*p==a==&a[0](地址),        

指针p存放首地址(又称数组名),对指针p取值得到首地址,*p==a(地址)

地址存放数组a第一个元素,对数组名a取值得到数组a的第一个元素,**p==*a==a[0](值),

**p==*a==*&a[0]==a[0](值),所以*&a[0]==a[0](值),所以*&两者可以抵消掉。

那么*(*(p+1))呢?

(p+1)是指针偏移1,是存放了第二个元素的地址,*(p+1)是取出第二个元素的地址,

*(p+1)是第二个元素的地址,是存放了第二个元素,*(*(p+1))是取出第二个元素,

*(*(p+1))==a[1]==*&a[1],就是值

*(p+1)+2,是第二个元素的地址偏移2

*p+2,是第一个元素的地址偏移2

接下来讲一下二维数组:

int a[2][3]={

{1,2,3},

{2,3,4}

};

刚刚讲到二维数组可以当作一维数组,意思是说二维数组的每一行就是二维数组的每个元素,第一行数组就是第一个元素,以此类推。

a是数组名,可在二维数组里我们可以把它当指针看,它指向第1行的一维数组,

a看作指针,

对它取值,得到第一行数组a[0]第一个元素a[0][0]的地址,也就是*a==a[0](地址) 

对地址取值,得到值,也就是**a==*a[0]==a[0][0](值)

a+1,是指针,就是指向第2行的一维数组,

*(a+1)==a[1](地址)(数组名)

*(*(a+1))==*a[1]==a[1][0](值)

*(a+1)+2,第2行的一维数组的第一个元素的地址偏移2(a[1]+2),也就是&a[1][2](地址)

*(*(a+1)+2),是取出地址&a[1][2]的值,也就是*(*(a+1)+2)==*&a[1][2]==a[1][2](值)

a看作数组名,我们定义一个数组指针int (*p)[5]=a; ,利用数组名把a[0][0]的地址赋给指针p:

int a[2][3]={{1,2,3},{2,3,4}};

int (*p)[5]=a;

/ /a是第一行数组a[0]的地址(二维数组的第一个元素的地址),不是整个数组a的地址,另外,这里写作 int (*p)[5]=&a[0]; 也对 

/ / a[0]是第一行数组a[0]第一个元素a[0][0]的地址(一维数组的第一个元素的地址),a[0]==&a[0][0]

---error---(*p)[5]=a;  / /不能这样写,会报错

以下代码段帮助理解:上述地址的值都是相同的,但是意义不一样而已,我们只是利用它的值,所以意义不同也没事,只为了赋予指针&a[0][0],只不过用int (*p)[5]=a; 的形式赋予指针地址罢了。

#include 
int main()
{
	int a[3][5] = {{1,2,3,4,5},
				   {2,3,4,5,6},
				   {3,4,5,6,7}};
	int (*p)[5]=a;
	printf("%pn%pn%pn%pn%pn%p",a,*a,&a[0],a[0],&a[0][0],&a) ;
	//a,第一行数组a[0]的地址(二维数组的第一个元素的地址) ==&a[0], 数组名是地址 
	//*a,数组名是指针?是的,可以这么认为 
	//a[0],第一行数组a[0]第一个元素a[0][0]的地址(一维数组的第一个元素的地址) ==&a[0][0],数组名是地址 
	//&a,整个数组a的首地址?对,万物都有地址 
}

运行结果:

如图显示,地址的值都相同,我们可以利用,虽然彼此意义可能不同,但我们只要值。

int (*p)[5]=a;也可以写成

int (*p)[5]=&a[0];

int (*p)[5]=*a;  

int (*p)[5]=a[0];

int (*p)[5]=&a[0][0];

p指向包含5个元素的一维数组,指向第1行的一维数组,指针p存放了地址(数组名a[0]),

对p取值就是*p==a[0](地址),

**p就是取出*p(地址)所存放的值,也就是**p==**a==*a[0]==*&a[0][0]==a[0][0](值)

那么*(*(p+1))呢?

*(p+1)是取出指针p+1所存放的地址(数组名a[1]),也就是*(p+1)==*(a+1)==a[1](地址),

*(*(p+1))是取出地址*(p+1)所存放的值,*(*(p+1))==**(a+1)==*&a[1][0]==a[1][0](值)

小题目可以结合做一下:

编程实现,将二维数组arr中第1列与最后一列的元素对调,第2列与倒数第2列的元素对调,依此类推,输出原始数组及调换后的数组。要求,定义行指针p使其指向二维数组arr,而对二维数组的所有操作都必须通过p进行。

例如:若数组arr的原始数据是:

    1 2 3 4 5

    2 3 4 5 6

    3 4 5 6 7

则调换后的数组如下:

    5 4 3 2 1

    6 5 4 3 2

    7 6 5 4 3

答案:

#include 
int main()
{
	int arr[3][5] = {{1,2,3,4,5},
				     {2,3,4,5,6},
					 {3,4,5,6,7}};
	int i, j; 
	int (*p)[5]=arr;//第一行数组的地址(二维数组的第一个元素的地址) 
	int temp;
	
	for(i = 0; i < 3; i++)//行 
	{	
		for(j = 0; j < 5; j++)//列 
		printf("%d ",*(*(p+i)+j));//*(p+i)是第i+1行的地址,*(p+i)+j,第i+1行第j+1列的地址, *(*(p+i)+j)),第i+1行第j+1列的值 
		printf("n");  
	}
	printf("对调结果如下:n");

	for(i = 0; i < 3; i++)//行 
	{
		for(j = 0; j < 2; j++)//列 
		{
			temp = *(*(p+i)+j);	//1行1列,1行2列,2行,3行 
			*(*(p+i)+j) = *(*(p+i)+4-j);//1行5列,1行4列 
			*(*(p+i)+4-j) = temp;//一行对换后,再下一行对换 
		}
	}

	for(i = 0; i < 3; i++)
	{
		for(j = 0; j < 5; j++)
		printf("%d ",*(*(p+i)+j));
		printf("n");  
	}
	 
	return 0;
}

最后,

总结一下:

指针的作用:赋予指针地址,一般是首地址,然后执行p+1...等操作,使指针偏移,指向某个值的地址,再用 *(取值运算符)对指向的地址取值,得到指向的值,一般用于调用数组的元素,也就是调用值。

那么为什么调用一维数组int a[ ]用int *p=a;就可以将地址&a[0]赋予指针p,而二维数组int a[ ][ ]要用int (*p)[ ]=a;的形式来把地址&a[0][0]赋予指针p呢?

其实很简单啊,

int *p=a,左边是一个指向一个int类型的指针,右边是一个元素的地址(一维数组的第一个元素的地址),一对一;

int (*p)[ ]=a;左边是一个指向存放int类型的数组的指针,数组包含不止一个元素吧,右边是一个数组的地址(二维数组的第一个元素的地址),数组对数组。

再次总结!

以上所有就是用指针调用数组元素!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/698280.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号