数组与指针之一

二维数组与指针(详解)_二维数组指针-CSDN博客

先讲数组与数组指针——

从数组与指针组合来看。

看一维数组部分:

借鉴其代码并做一些扩充,原文中打印结果也是不全,这里贴全:


#include <stdio.h>

int main()
{
	int(*p)[3];
	/*定义了一个数组指针,指向了一个数组长度为3的一维数组,注意是指向一个数组,所以赋值给他的地址要是数组类型的地址
	  可以这样理解:一维数组名就是一个指针这里只是用指针的形
	  式代替了数组名 ,注意这里的3要和指向的数组长度相同
	*/

	int a[3] = { 1,2,3 };
	p = &a;
	/*
	将数组a地址赋值给p,此时(*p)[i]相当于a[i],注意不能写成p=a,或者p=&a[0]
	因为指针p是指向一个数组,p=a表示p指向首个元素的地址,虽然&a,&a[0],a
	的结果是一样的(这是因为数组一般用其首元素地址表示)
	*/

	printf("数组指针指向一维数组的遍历:\n");
	for (int i = 0; i < 3; i++)
	{
		printf("%d\n", (*p)[i]);
	}

	/*这里要用指针遍历输出a不能用*(p+i)方式输出,
	  因为p表示数组a的地址(一般用数组中首个元素地址表示),
	  p++表示p要增加3*4个字节长度(3为数组指针指定的长度,4为int所占空间大小)
	*/

	printf("--------------------------\n");
	printf("a=%d\n", a);//输出a的第一个元素地址
	printf("&a=%d\n", &a);//输出a的地址
	printf("*a=%d\n", *a);
	printf("a+1=%d\n", a + 1);//
	printf("&a+1=%d\n", &a + 1);//
	printf("p=%d\n", p);//p指向了数组a,所以输出为a的地址(一般用数组中首个元素地址表示)
	printf("*p=%d\n", *p);//既然p指向了数组a,那么*p则为数组a本身(一般用数组中首个元素地址表示)
	printf("p+1=%d\n", p + 1);
	printf("*p+1=%d\n", *p + 1);
	printf("*(p+1)=%d\n", *(p + 1));//,运用公式*(p+1) == p[1],可以想象成刚好超过a长度的那个地址,p+1表示p要增加3*4个字节长度(3为数组指针指定的长度,4为int所占空间大小)==*(p+1)
	printf("**p=%d\n", **p);//p指向a,*p表示a本身(一般用数组中首个元素地址表示),那么**p表示*a,表示数组首元素。
	printf("p[0]=%d\n", p[0]);//p[0] == *p ,*p又是a本身,所以输出a首元素地址
	printf("*p[0]=%d\n", *p[0]);//既然p[0]为数组首元素地址,那加上个*就为a的首元素 
	printf("p[1]=%d\n", p[1]);
	printf("*p[1]=%d\n", *p[1]);

	return 0;
}

本地电脑运行结果:

数组指针指向一维数组的遍历:
1
2
3
--------------------------
a=-178980952
&a=-178980952
*a=1
a+1=-178980948
&a+1=-178980940
p=-178980952
*p=-178980952
p+1=-178980940
*p+1=-178980948
*(p+1)=-178980940
**p=1
p[0]=-178980952
*p[0]=1
p[1]=-178980940
*p[1]=-858993460

 

一般还是可以准确理解,比较难理解的是:

1、

a和&a,表示的地址是一样的,但是意义却不一样,看后面a+1和&a+1结果可知,a表示数组首元素的地址,是按元素为单位计的,而&a表示数组首地址,虽然和首元素的地址一样,但却是按数组为单位计的,所以&a+1是地址增加了一个数组共12个字节。

也就是,取数组地址,要用&(数组名),其实和变量取地址一样。

而数组名,表示数组首元素地址,所以下文有*a结果是首元素值。

2、

p和*p表示地址也一样,但是其实和上面1中含义一样,即,p表示的是&a,是数组地址,*p表示的正是第一个元素地址,所以,p+1表示数组单位加1,而*p+1表示数组第一个元素地址加1。也就是说,对数组指针取值,得到首元素的地址!则再进行取值,则得到首元素值。即打印的:**p=1. 

3、

p[0]和*p[0],同样也很容易区分了。p[0]表示&a[0],即表示&a+0,实际就是数组地址。则*p[0]表示对数组地址取值,如2中所述,表示数组首元素地址了。至于p[1],其实就是&a+1,见1中所述。

二维数组部分:

同样,对原代码进行扩充,打印完全结果:

代码:


#include <stdio.h>
int main()
{
	int a[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
	int(*p)[4];//4要和二维数组的列元素个数相同 
	
	printf("a=%d\n", a);
	printf("&a=%d\n", &a);
	printf("*a=%d\n", *a);
	printf("a+1=%d\n", a + 1);
	printf("&a+1=%d\n", &a + 1);
	printf("*a+1=%d\n", *a + 1);

	p = a;//a代表数组首行地址
	printf("p=%d\n", p);//p==a,p就为a的首行地址
	printf("*p=%d\n", *p);//*p == *a 为数组首元素地址
	printf("**p=%d\n", **p);//**p == **a 为数组首元素 
	printf("p+1=%d\n", p + 1);// p+1 == a+1;为第1行(有第0行)
	printf("*p+1=%d\n", *p + 1);
	printf("**p+1=%d\n", **p + 1);

	printf("*(p+1)=%d\n", *(p + 1));
	printf("**(p+1)=%d\n", **(p + 1));

	printf("--------------------\n二维数组的遍历\n");
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%d ", *(*(p + i) + j));//通过上面的公式我们可以写成p[i][j] 或者*(p[i]+j)在下面数组的遍历我们都会一一使用
			if (j == 3)
				printf("\n");
		}
	}

	return 0;
}

结果:

a=-1391397304
&a=-1391397304
*a=-1391397304
a+1=-1391397288
&a+1=-1391397256
*a+1=-1391397300
p=-1391397304
*p=-1391397304
**p=1
p+1=-1391397288
*p+1=-1391397300
**p+1=2
*(p+1)=-1391397288
**(p+1)=5
--------------------
二维数组的遍历
1 2 3 4
5 6 7 8
9 10 11 12

 

解析:

1、

首先,这里定义数组指针,竟然和指向一维数组是一样的。那么是否说明数组指针只能指向一维数组呢?这里**(p+1)值为5,可见其偏移单位是按照一维数组为单位的,这里是一行。

2、

在指针赋值时,再不能像一维数组p=&a,而只能是p=a。程序中注释,a表示数组首行地址,而后面也验证了,a+1就是相对于a偏移了16个字节,即一行。这是否说明,二维数组的指针,是否不能直接指向二维数组本身,而只能指向其首行呢?

3、

同样,我们对数组取地址,即&a,得到的是数组整体的地址,所以&a+1相对于&a偏移48个字节,即整个二维数组的字节数。那么,是否说明可以定义这种指向整个数组的指针?也就推翻了2中猜测?

4、

对于理解了p表示二维数组首行地址,且此时是数组地址,那么对于p、*p 、p+1、 *p+1 、*(p+1)以及**p、 **(p+1)等就按照上面一维数组进行分析了。举例,p+1表示第一行为单位偏移一个单位,其实是第二行地址,*p表示对第一行的一维数组地址取值,则表示首元素的地址,则*p+1表示首行第二个元素地址,**p表示首元素值。*(p+1)表示第二行首元素地址,**(p+1)表示第二行首元素值。

5、

所以,遍历数组时,注意先按照行偏移,表示行地址,行地址取值,表示行的首元素地址,首元素地址再加列偏移,表示某行某列的地址,再取值,则表示某行某列的值。所以用*(*(a+i)+j)。

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值