通常进行二维数组遍历都会想到用二级指针,今天试了一下竟然会报错。
代码如下:
#include <stdio.h>
#include <stdlib.h>
void traversalArray(int **a,int row,int column)
{
for(int i = 0;i<row;i++)
{
for(int j = 0;j<column;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
}
int main(int argc,char **argv)
{
int b[3][4] = {{0,1,2,3},
{4,5,6,7},
{8,9,10,11}};
traversalArray((int **)b,3,4);
return 0;
}
出现这个错误我们来进行分析一下。
首先我们先来做一个例子:
int x = 100;
int *y = &x;
int **z = (int **)y;
printf("%d\n",*z);//100
printf("%d\n",**z);//报错
通过上面的例子是不是觉得和用二级指针遍历二维数组b一样的错误。
a == b == *b == &b[0][0] 这个是成立的对吧。
既然a == &b[0][0]了,那*a == 0了(就是二维数组b的第一行第一列的元素),那么再对0取*就是**a了,是不是就出现访问到了操作系统的内存区域了,发生冲突,Windows就直接把你干掉了。是不是和上面的**z一样的道理。
我们再来分析一下二维数组b的类型,int b[3][4]的类型为int (*)[4]的数组指针,表示一个指针指向每行有4个sizeof(int)个字节,每次移动sizeof(int)字节,更重要的一点是,它的内存地址是连续的。
那从上述分析来看是不是觉得二维数组其实就是一个一维数组的加强版本。既然是这样那我们就把int **a强制转换成int *a,然后再每次移动sizeof(int)个字节大小去遍历。
那我们再来修改一个traversalArray这个函数。
#include <stdio.h>
#include <stdlib.h>
void traversalArray(int **a,int row,int column)
{
for(int i = 0;i<row;i++)
{
for(int j = 0;j<column;j++)
{
/*
先来分析一下这句代码的意思
(int *)a
先将int **,转换为int *。int **是指向int *,
每次移动sizeof(int *)个字节大小;
int *是指向int,每次移动sizeof(int)个字节大小。
通过上面的分析肯定会有人疑问,比如都在32位的系统中,
指针移动是4个字节,int也是4个字节,那么为什么还要
强制转换呢?
同过上面的分析我们已经说了,a == b == *b == &b[0][0]
虽然步长一样,但是指向的内容是不一样的,所以需要在这
里进行强制转换。
i * column
这句话就是代表向前移动多少个(i * column) * sizeof(int)
字节大小的步长
比如第一行那就是1 * 4 * sizeof(int),
第二行那就是2 * 4 * sizeof(int)....以此类推
+ j
这句话就是比如我在第一行的内存地址中
(int *)a + 0(i) * 4(column) + 0(j)
每次向前移动sizeof(int)个字节,就得到第一行第一列的内存
地址了,然后再在最外层取*最终得到值。
*/
printf("%d ",*((int *)a + i * column + j));
}
printf("\n");
}
}
int main(int argc, char **argv)
{
int b[3][4] = { {0,1,2,3},
{4,5,6,7},
{8,9,10,11} };
traversalArray((int **)b, 3, 4);
return 0;
}
成功的将二维数组遍历了。