C/C++中二维数组和指针关系分析:https://blog.csdn.net/zhouxuguang236/article/details/12256321
其实,在C/c++中没有所谓的二维数组,书面表达就是数组的数组,猜想是为了表述方便才叫它二维数组。
一、二维数组一维化其实我这里也只是表述的方便才叫这么一个题目,我们怎么利用一个数组的访问方式来访问二维数组呢?下面来看一个具体的例子。
首先,定义一个二维数组。
int iArr[2][3]={0,1,2,3,4,5}; 我们可以用一个指向int型的指针变量来访问这个数组,下面的代码是将数组一维化: int* p = iArr[0]; 上面的iArr[0]就是代表第一个数组的首地址,由于二维数组在内存中的存储也是先行后列的方式,所以第二行也紧跟第一行之后,这样就可以用p来访问数组的元素值了,访问的方式有下标和指针方式。printf("%d,",p[3]);
printf("%d\n",*(p+3)); 最后输出的结果都是3。讲完了一维化之后,下面来继续看二维数组的函数名到底是什么意思? 二、关于二维数组名的探索 我们可以打印出一些地址看看: printf("iArr = %d,iArr[0] = %d,&iArr[0][0] = %d,iArr[0][0] = %d",iArr,iArr[0],&iArr[0][0],iArr[0][0]); 从结果可以看出: 二位数组名iArr 首行地址 iArr[0] &iArr[0][0]三个地址相等; &Arr 代表整个数组首地址,加1代表加整个数组大小 Arr &Arr[0] 代表第一行首地址,加1代表加整行的大小 Arr[0], *a ,&a[0][0]代表第一行首地址,加1代表加一个元素的大小 其实iArr二维数组名是一个数组指针,数组指针是指向一个数组首地址的指针,它实际上也是一种指针类型,类似于函数指针。它声明如下:int (*pArr)[3]
它说明pArr是一个数组指针,它指向的是一个数组元素为int类型并且数组元素的个数为3的一个数组指针,奇怪,中间的怎么还有一个括号是啥玩意?呵呵,这个括号还真是不可少的。少了它就变为另外一种类型了:指针数组。指针数组是数组类型,代表数组的每一个元素是指针类型,它声明如下: int *pArr[3]。 大小: sizeof(iArr)=24, sizeof(iArr[0]) = 12; sizeof(iArr[0][0]) = 4; 既然二维数组的数组名是指向第一行数组的首地址,我们也叫它行指针。那么我们可以用这种数组名或者指针来访问二维数组的元素。 int (*pArr)[3] = iArr; 下面,我要访问第一行第二列的元素,我可以用下面的代码来访问 *(*(pArr+1) + 2) 也可以用数组名来访问: *(*(iArr+1) + 2) 首先,pArr是一个指向数组的指针,在这个指针上加减一个整数都是移动整行,而不是一个元素。比如说,pArr+1代表的现在指针已经指向第一行元素了,也就是实际中的第二行,而要取得指针所指的对象,就要用到解引用运算符*,所以*(pArr+1)就代表第一行数组,是整个这一行元素就取到了,那现在要取这一行的第二个元素,只须将指针再移动两个元素,即*(iArr+1) + 2,这样就指向了这个元素的地址,再解引用取得元素的值即可。 三、作为函数参数 (将二维数组当作参数的时候,必须指明所有维数大小或者省略第一维的 ,但是不能省略第二维或者更高维的大小,这是由编译器原理限制的)一维数组名作为函数参数实际上是退化为指针,二维数组作为函数参数又有什么不同呢?在用二维数组名作为参数传递时容易出现Segmention Error。这是因为不能正确为二维数组中元素寻址的问题,正确的方法如下:
[cpp] view plaincopy#include <stdlib.h>
#include <stdio.h> #define N 4 void testArray(int *a, int m, int n) { for(int i = 0; i < m; ++i) for(int j = 0; j < n; ++j) { printf("a[%d][%d] = %d\n", i, j, *(a+i*n+j)); } } int main() { int a[2][N] = { {1, 2, 3, 4}, {5, 6, 7, 8}}; testArray((int *)a, 2, N); }
1. 将二维数组的两个维度用变量的形式传递过去
如下所示: [cpp] view plaincopy#include <stdlib.h>
#include <stdio.h> #define N 4 void testArray(int **a, int m, int n) { for(int i = 0; i < m; ++i) for(int j = 0; j < n; ++j) { printf("a[%d][%d] = %d\n", i, j, *((int*)a + i * n +j)); } } int main() { int a[2][N] = { {1, 2, 3, 4}, {5, 6, 7, 8}}; testArray((int **)a, 2, N); }此时在子函数中不能使用a[i][j]的形式访问数组元素,因为数组元素都是顺序存储,地址连续,在使用a[i][j]访问数组元素时,无法顺序访问到指定的元素,所有我们只能通过计算指定所要访问的元素。
2、用指向一维数组的指针变量,如下例子所示:
[cpp] view plaincopy#include <stdlib.h>
#include <stdio.h> #define N 4 void testArray(int (*a)[4], int m, int n) { for(int i = 0; i < m; ++i) for(int j = 0; j < n; ++j) { printf("a[%d][%d] = %d\n", i, j, *(*(a+i)+j)); //printf("a[%d][%d] = %d\n", i, j, a[i * n +j]); } } int main() { int a[2][N] = { {1, 2, 3, 4}, {5, 6, 7, 8}}; testArray(a, 2, N); } int (*a)[N] 表示指向一维数组的指针变量,即a所指向的对象是含有4个整型元素的数组。注意 () 不能少,若定义成:int *a[N] 则表示有一个一维数组a[N],该数组中的所有元素都是 (int *)类型的元素。
在这里,在子函数中访问二维数组中的元素可以用 a[i][j] 或者 *(*(a+i)+j) 在这种情况下(*(a+i))[j],a [i * n +j]);,*(*(a+i)+j),a[i][j],*((int*)a + i * n +j)都可以进行访问。