对c语言二维数组指针的理解

最近在学习c语言数组和指针的时候卡了很久,有一个问题始终想不通:

//定义一个二维数组
int arr[ROWS][CLOS];

数组可以以下方式进行遍历:

//数组赋值...略
int newline = 1;
for (int*  p = &arr[0][0]; p < &arr[ROWS-1][CLOS]; p++)
{
	printf("%d ", *p);
	if (newline++ % 10 == 0 )
	{
		printf("\n");
	}
}

这个书上的解释是:c语言按照行主序来存储二维数组;换句话说就是先是存储第0行,再是第q一行…
如图:
在这里插入图片描述
所以可以按照一维数组的方式对数组进行遍历。
于是我想到了另一种方法:

for ( int *p = arr; p < arr + ROWS*CLOS; p++)
	{
		printf("%d",*p);
	}

按照理解二维数组arr打印时可以看成一个以为数组,那么arr+1就是下一个元素的位置,一共有ROWS*CLOS个元素,所以这样打印是没有问题的。
但是打印出的结果是把arr里的数据打印完过后,还打印了很多个不知道哪里来的超级长的数值。这个说明:
我对指针加减并没有理解正确,指针加一确实是指向了下一个数字的位置,但是这是个二维数组,别忘了arr[0] 和&arr[0][0]的意义是不一样的(虽然它们的数值是一样的)它们的类型是不同的,类型不同时指针加一会有很大的区别。
于是做了以下实验—打印数组的各种地址:

实验一:

		printf("-----------------------\n");
		printf("arr  :%p\n", arr);
		printf("arr+1:%p\n", arr+1);
		printf("arr+2:%p\n", arr+2);

		printf("-----------------------\n");
		printf("arr[0]:%p\n", &arr[0]);
		printf("arr[1]:%p\n", &arr[1]);
		printf("arr[2]:%p\n", &arr[2]);
		printf("arr[0]+1:%p\n", arr[0]+1);
		printf("arr[0]+2:%p\n", arr[0]+2);

		printf("-----------------------\n");
		printf("arr[0][0]: %p\n", &arr[0][0]);
		printf("arr[0][1]:%p\n", &arr[0][1]);
-----------------------
arr  :000000D0EBDEF690
arr+1:000000D0EBDEF6B8
arr+2:000000D0EBDEF6E0
-----------------------
arr[0]:000000D0EBDEF690
arr[1]:000000D0EBDEF6B8
arr[2]:000000D0EBDEF6E0
arr[0]+1:000000D0EBDEF694
arr[0]+2:000000D0EBDEF698
-----------------------
arr[0][0]: 000000D0EBDEF690
arr[0][1]:000000D0EBDEF694

我这里ROWS == CLOS == 10,由于arr数组存放的是int型数值即4个字节,arr是一个二维数组,其实也是一个一维数组:arr[0]是一个数组 arr[1]是一个数组…arr的每个元素都是一个长度位ROWS的一维数组。
通过对比打印结果 有结论:
1.arr(二维数组的首地址)+1是一次加了40个字节,即每次+1都会跳到下一行的首地址(下一个一维数组元素的首地址)一次跳了4*ROWS个字节。
2.arr[0]每次加一增加了4个字节的地址,所以arr[0]也跳到了下一个元素,即arr[0]1]的位置, arr[0]的元素是int类型的值。

实验二:

		printf("-----------------------\n");
		int* p_arr = arr;
		int* pp = &arr[0];
		printf("arr       :%p\n", arr);
		printf("&arr[0]   :%p\n", arr[0]);
		printf("&arr[0][0]:%p\n", &arr[0][0]);
		printf("-----------------------\n");
		printf("pp  :%p\n", pp);
		printf("pp+1:%p\n", pp + 1);
		printf("pp+2:%p\n", pp + 2);
		printf("-----------------------\n");
		printf("p_arr  :%p\n", p_arr);
		printf("p_arr+1:%p\n",p_arr+1);
		printf("p_arr+2:%p\n",p_arr+2);
arr       :000000D7C70FF590
&arr[0]   :000000D7C70FF590
&arr[0][0]:000000D7C70FF590
-----------------------
pp  :000000D7C70FF590
pp+1:000000D7C70FF594
pp+2:000000D7C70FF598
-----------------------
p_arr  :000000D7C70FF590
p_arr+1:000000D7C70FF594
p_arr+2:000000D7C70FF598

这次可以得到如下结论:
1.arr 、&arr[0] 、&arr[0][0]三个指针的值是相同的。
2.指向arr的指针p_arr+1时并不是像arr+1一样一次加上ROWS4个字节的长度 ( 原因是:定义时p_arr的类型是int型的,所以编译器默认的将p_arr指向的内存看成是存放 int类型元素的内存块,所以p_arr虽然指向了arr但是+1时并不是加上一个一维数组大小的长度,如果要让p_arr+1一次增加ROWS4个字节长度 需要定义成:int(p_arr)[ROWS] 这代表了指针p_arr指向长度为ROWS的int数组,这样p_arr+1时会一次加上数组长度ROWS4个字节的长度 )。

实验三:

		int (*p_arr)[ROWS] = arr;
		printf("p_arr  :%p\n", p_arr);
		printf("p_arr+1:%p\n",p_arr+1);
		printf("p_arr+2:%p\n",p_arr+2);

可以看到将p_arr指向nt ()[ROWS]类型时p_arr本身的类型是int()[ROWS],且p_arr+1 增加了ROWS 4个字节的长度。
结论:
1.实验二的第二个结论没问题。

实验四

将指向int类型的指针–指向char,这里把c赋值为26个小写字母:

		char c[26];
		int index = 97;
		for (int i = 0; i < 26; i++)
		{
			c[i] = index++;
		}
		for (int i = 0; i < 26; i++)
		{
			printf("%c", c[i]);
		}

		int* p_c = c;
		printf("%c", p_c + 1);

我们知道char类型一般占1个字节,int类型占4个字节,经过前三个实验可以推论处p_c+1时 由于p_c的指向的类型是int型,所以p_c会增加4个字节的位置,所以会打印第5个字母:e

abcdefghijklmnopqrstuvwxyz
----------------------
e

结论:
1.实验三的结论是对的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值