早20多天,有网名为chaozhisong的同学给我来信,问下面的程序为什么会出现段错误?

#include<stdio.h>
void test4(void** a)
{
int i,j;
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
printf("%d\n",((int**)a)[0][j]);
}
}
int main()
{
int arr[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
test4(arr);
return 0;
}

  那几天挺忙的,等抽出时间看已经晚了,而程序里面指针绕来绕去的,搞了十多分钟,还有其他事等着,我不得不放弃了。

  我回复道:“我也没有时间继续找个正解了。通过论坛,求一下解释吧,那里有经验更丰富的高手。如果方便,届时告我一下结果。”

  其实,遇到程序中存在的问题时,找论坛是最快的,能看到的人也多,这个方式可以有。

  这样回复完后,我也已经有些忘记了。

  现在却收到了luochengguo的私信。他作出了解答,私信主题是“路人甲问题解答”。真好,好人万岁。

  下面就是路人甲的解答。

--------------------------------------------------------

  贺老师您好以及chaozhisong这位同学你好,刚刚恰巧逛贺老师论坛看到了这位同学的问题,我大概说一下,不对的请两位见谅:

  1. 首先我对这位同学的代码的目的有点模糊 , 基本应该觉得这位同学是想完整遍历这个二维数组,但是从代码实际情况看即使没有发生段错误也只能重复三次遍历并打印这个二维数组的第一行。

  2. 基础知识: 关于二维数组的遍历,一般以下三种方法都可以:

  a. void out(int *p, int n);

  b. void out(int *p, int row, int col);

  c. void out(int p[][4], int row); //等价于void out(int (×p)[4], int row);

  其实上面这三种方法你都能理解和实现,就看你对一维数组和二维数组的理解,包括二维数组本质就是多个一维数组的一维数组,以及你对指针和数组名的区别,包括一维数组名和二维数组名的实际意义,包括数组指针等这里一系列有关系内容的本质的理解和梳理了, 由于一一例出比较多,我就不多说了(如果这位同学对这些知识点比较模糊或

不能说出所有然,说明基础不扎实)。

  3. 如果第2点中的内容你真的全部理解和融汇贯通了, 其实这个问题你要有个正解应该没有任何问题

  4. 继续回到你的实际问题,如果你确实想遍历这个二维数组的第一行3遍,那就将错就错, 把你的代码改成没有段错误并能顺利遍历出来, 最小的改动可以如下:

void show(void **array)
{
int i;
int j;
int (*a)[3] = array;
for(i=0; i < 3; i++)
{
for(j=0; j < 3; j++)
{
printf("%d\n",a[0][j]);
}
}
}

  如果你本来是想遍历整个二维数组,那么改的方式就太多了,以下随意例出几种:


  方式一:


void show(void**array)
{
int i;
int j;
// for(i=0; i < 3; i++)
// {
for(j=0; j < 9; j++)
{
printf("%d\n", ((int*)array)[j]);
}
// }
}

  方式二:


void show(int array[][3]) //或void show(int (*array)[3])当然一般其实还有第二个参数就是行数n
{
int i;
int j;
for(i=0; i < 3; i++)
{
for(j=0; j < 3; j++)
{
printf("%d\n", array[i][j]);
}
}
}

  等等 其他各种改法, 主要就还是看你对第2点的理解了。


  5. 再次回到你实际问题,包括从上面的修改你也可以看出, 可能这位同学的问题还是出在基础知识不扎实,对数组和指针的异同理解不到位... 就从最基础的代码层面来讲,主要问题就出在((int**)a)[0][j])这里, 在对数组元素访问的之前其实此时a根本就已经不是一个数组名了, 被强转成了一个普通的二级指针, 一个普通的二级指针哪来的行和列,这个指针名字a在编译器看来已经失去了数组的意义了, 更没有了行和列的意义。对于这个普通的局部变量二级指针a, 根本就不知道要访问那块内存,当然段错误了(类似于你申明一个指针,却没有任何指向,然后去解引用操作(大概就这个意思),当然段错误)。


  什么各种内存图就不画了。。。。


  以上所有仅个人想法, 觉得不对请见谅。 只做基本的参考


----------------

  感谢路人甲的分享!