1. 索引遍历
(1)创建二维数组

(2)利用索引的方式进行遍历
①、二维数组第一种第一格式的索引遍历
arr[0]表示二维数组中的第一个一维数组;
arr[1]表示二维数组中的第二个一维数组;
arr[2]表示二维数组中的第三个一维数组;

所以外循环的循环次数,要小于二维数组的长度(在这里是小于3)。
for (int i = 0; i < 3; i++){}
当i=0时:
arr[i][0]表示一维数组0索引的数据,1;
arr[i][1]表示一维数组1索引的数据,2;
以此类推,所以内循环要小于一维数组的长度(这里是小于5):
for (int j =0; j < 5; j++){}
内循环循环体就是遍历一维数组即可:
printf(“%d”,arr[i][j]);
外循环循环体,内循环每完成一次代表第一个一维数组遍历完成,要进行下一个一维数组的遍历,为了方便阅读,要进行换行:
printf(“\n”);
完整代码:

在基本实现的代码中,我们可以发现,二维数组中的一维数组长度一样,并且在内循环的条件判断中,j < 5,其中的长度5,并不像之前的len是可以根据数组的长度来进行变化的,相当于这里的代码写的太死板了,所以要进行一下改进。
②、外循环的条件不变,如何计算内循环的循环次数?
还是一样,之前计算一个数组arr的长度,可以用这样的方式:
int len = sizeof(arr) / sizeof(int);
即:总长度 / 数据类型占用的字节个数
这里一样,由于我们用的是二维数组,要计算一维数组的长度,我们就要用到二维数组表示一维数组的方式:
int len = sizeof(arr[i]) / sizeof(int);
然后再把内循环的5,换成len即可:

第一种格式定义的二维数组有个弊端,一维数组的长度必须保持一样,否则内循环的遍历一维数组实现比较困难。
(2)二维数组第二种定义格式的索引遍历,即指针数组的遍历。
①、定义指针数组
首先要定义好3个一维数组,再把3个一维数组放到一个指针数组中:

这里int* arr[3] = {arr1,arr2,arr3};
核心原理,就是此时arr存储的是一维数组的首地址,并且一维数组都是int类型的,为了保持一致所以要定义一个int类型的指针数组arr,即int* arr[3]。
②、设置遍历
这里先演示一个错误情况

这里主要是内循环的长度计算问题。
在之前的学习指针数组的时候,有两个概念:
第一个:
即,arr参与计算的时候,会退化为第一个元素的指针,所以此时arr[i]在这里是一个指针,在x64Windows操作系统中,一个指针的大小为8字节,所以,在计算len的时候,就会导致结果为2。
即:8(指针的字节大小) / 4(int类型的字节大小) = 2
第二个:
sizeof运算的时候,arr不会退化,还是数组的整体,这里为什么没有退化?
由于我们在计算数组长度之前,把arr1-3都存入了指针数组arr中,在这一步中,arr退化成了第一个元素的指针,所以我们在之后计算长度的时候,用arr[0]其实获取的就是arr1的指针。
解决方法:可以在存入指针数组之前计算每个数组的长度,然后再定义一个数组存储数组的长度。

把lenArr[i]当成内循环的判断条件即可

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
2. 指针遍历
(1)二维数组第一种格式的指针遍历
①、二维指针的定义格式
如何定义指针记录二维数组的值?
定义的二维数组

二维数组在内存中的表示:

二维数组内部一维数组的数据类型为int,一维数组的指针类型为int*;
二维数组的数据类型为int[5],这里表示的是二维数组是int类型,里面一维数组的长度为5。
二维数组的指针类型为:int[5]*
所以在定义二维数组的指针(一般称为二维指针)时,要按照下面的格式书写:
二维指针的定义格式
数据类型 * 指针名 = arr;
例如:int[5]* p = arr;
但是一般会把[5]放在指针名的右边:
int*p[5] = arr;
此时看上面的定义,由于和数组的定义相似,所以还需要*p用小括号包裹起来,注意,这里的*是指针标记,不是解引用。
int(*p)[5] = arr;
②、二维指针如何获取一维数组的指针
还是上面一样的二维数组

二维数组在内存中的表示:

如果要获取第一行的一维数组,需要对二维指针进行解引用,此时解引用表示的是一维数组的首地址值,即 *p,例如:
int* temp = *p;
此时指针temp记录的就是一维数组的首地址值,因为arr参与计算会退化为第一个字节的指针。

获取下一个的一维数组的首地址值,用二维指针p + 1即可,此时移动的步长为20字节:
5(一维数组长度)* 4(int类型的字节大小)
向右移动20个字节后,就能获取到第二个一维数组的首地址值。

③、获取到了一维数组的首地址后,怎样遍历。
这里不考虑使用第三方临时指针变量来存储一维数组的首地址值。
首先设计一个for循环,外循环还是一样,循环的次数要小于二维数组的长度。
内循环要小于一维数组的长度。


内循环中的printf(“%d”,*(*p + j));
首先*p + j的意思是,首先*p,解引用得到一维数组的首地址值,后面的j就是索引,即偏移量(首地址 + 往后进行偏移)。
当j = 0,偏移0个单位,获取的就是索引0的首地址;
当j = 1,偏移1个单位,获取的就是索引1的地址值;
以此类推
*(*p + j)的意思是,对获取到的索引地址值再次解引用,此时获取到的就是索引对应一维数组中的数据。
例如当 j = 0,偏移0个单位,获取的就是索引0的数据,假如此时我们在遍历第一个一维数组的值,那么这个数据的值就为1;以此类推。
当内循环结束一次,外循环就要打印换行
printf(“\n”);
同时,二维指针要+1,获取下一个一维数组的首地址。
(2)指针数组的指针遍历
①、先定义一维数组,并存到指针数组中

此时指针数组arr,记录的就是arr1,arr2的首地址。
②、定义二维指针用来获取指针数组
格式:数据类型* 指针名 = arr;
例如:
int** p = arr;
③、遍历和第一种方式一摸一样

但是其实这里的*(*p + j)可以不用写这么麻烦,也可以直接写
*(p[i] + j)
