关于二维数组:
int arr[2][3]={1,2,3,4,5,6};
前言:可以将二维数组理解为"数组的数组"。数组名a为行指针。
从二维数组角度看,arr代表了二维数组首元素的地址。现在首元素不是一个单独的变量,而是一个一维数组。因此arr代表了首行的首地址。a+1就是下一行的地址。也可以表示为a[1],同理都有a[0],a[2]。分别表示第0行和第二行的地址。既然他们都是地址(也就是一维数组名,C语言规定一维数组的数组名代表了数组首元素的地址),a[0]也就表示了第0行第一个元素的地址。也就是&a[0][0]。a[1]的值就是&a[1][0]。
表示0行1列的地址时,用a[0]+1 表示,它与a+1的区别在于a[0]是0行的首地址,a[0]+1是在一维数组中操作,+1 也就是加了sizeof(int) 大小。在a+1时候,因为二维数组可以理解为数组的数组,也就是一个数组里面的变量是一个个的数组。则此时这个a数组名字也就相当于一维数组的名字。它代表了首元素的地址,这是多次提到的。给a+1,相当于加到了a数组的第二个元素,而每个元素其实是一个数组。也就是跨过了一行。此时到了第一行。此时的地址就是a+sizeof(int)*列数。 要想找到1行1列的地址时,也就是a[1]+1。要注意的是a[1]的地址同时也是数组里面元素数组的首地址。为了便于理解,里面抽象了两个一维数组。一个是二维数组抽象为一个数组的数组,第二个就是数组里面的元素是一个数组。在内存中,他们的内存单元其实是连续的,这里只是为了方便理解。前面都是用[]取值,我们也可以用*号。0行1列的地址也可以表示为*(a+0)+1,1行1列地址为*(a+1)+1,0行1列的值为*(*(a+0)+1),对地址取值就是所指向的对象的值。(此为补充理解,理解这段解释后基本已经理解了二维数组,这段是在我后面总结加入的理解,与下面内容有很多重复。但是也可以看看,加强理解)
数组名是:arr : int(*p)[4]; // 首行的地址 ,数组指针,也就是指向数组的指针,此处p为指向4个int变量的数组
arr+1: int(*p)[4]; //第二行的地址,
arr[0]: int * //arr中第0列的元素地址,也就是第一个元素 的地址,可以理解为取出来了一个一维数组,一维数组名字为指向数组首元素的指针(并不是真的指针,可以这样理解),所以此处取值后仍然为int *。
- arr[0]+1: int * ; //arr中第0列元素下一个元素的地址 arr[0][1]
- *arr: int ; // 第一个元素的值
- *( *(arr+1)+1):int // 首先是arr+1 指向了第二行的地址,解引用后为int* 指针(相当于一维数组的名字),然后+1则相应的列+1,然后解引用,int*解引用取到值。也就是arr[1][1]的值。
- //上面需要好好理解
关于三维数组:
int arr[3][2][2]={0,1,2,3,4,5,6,7};//相当于3个2 * 2 的二维数组
printf("%d %d %d %d\n",&arr[0],&arr[0][0],&arra[0][0][0],&array); //结果都是相同的,说明其指向都是相同的。
//如果说把三维数组比作一个立方体的话,那么这个立方体底边是个2*2的正方形,高为3
//注意:三维数组的高维度是写在最前面的,也就是立方体的h
按照理解那么此三维数组一共三层,第一层为 arr[0][0][0],arr[0][0][1],arr[0][1][0],arr[0][1][1], 第二次为 arr[1][0][0],arr[1][0][1],arr[1][1[0],arr[1][1][1],第三层类似。需要注意的是第三层会默认初始化为0。
可以发现 假设没有高h后,也就是没有第一列维度后,数组是一个二维数组。那么arr指向的就是一个二维数组。
1.arr:int (*p)[][]; // 第一层第一个元素地址
2.arr+1:int(*p)[][]; //指向了第二层
3. arr[0]:int(*p)[] ; // 解引用后 为一个数组指针,作用和二维数组的行指针相同。可以对比学习。
4.arr[0][0]:int *; //继续解引用后为一个int指针,此时已经为一维数组,相当于取到了一维数组的名字,此时还是指针,
5.arr[0][0][0]:int ; //显而易见,此时取到一维数组的第一个值,也就是二维数组的第一个值,也就是三维数组的第一个值。 要好好分析理解。
总结:
1.一维数组名字代表指向变量的指针,二维数组名字代表指向数组的指针,三维数组名字代表指向了二维数组的指针。关系是层层递进的。只要理解了二维与一维的关系,那么二维与三维也就很好理解。四维也不在话下。
2.在面对问题时,考虑二点:
优先级:()>[]>*;
若是指针(*)看指向什么东西,若是数组([]),看数组长度和类型,若是函数 (()),看参数列表和返回值。这个是函数指针,指针函数。