路人甲的帮助——C指针的指针引发的错误

简介:   早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",(

  早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, 根本就不知道要访问那块内存,当然段错误了(类似于你申明一个指针,却没有任何指向,然后去解引用操作(大概就这个意思),当然段错误)。
  什么各种内存图就不画了。。。。
  以上所有仅个人想法, 觉得不对请见谅。 只做基本的参考

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

  感谢路人甲的分享!




==================== 迂者 贺利坚 CSDN博客专栏=================
|== IT学子成长指导专栏 专栏文章的分类目录(不定期更新) ==|
|== C++ 课堂在线专栏  贺利坚课程教学链接(分课程年级) ==|
|== 我写的书——《逆袭大学——传给IT学子的正能量》    ==|
===== 为IT菜鸟起飞铺跑道,和学生一起享受快乐和激情的大学 =====




目录
相关文章
|
6月前
|
存储 算法 C++
函数的指针:理解与应用
函数的指针:理解与应用
25 1
|
6月前
|
存储 C++
C++程序中的函数与指针
C++程序中的函数与指针
23 1
|
6月前
空指针和野指针的区别和定义
空指针和野指针的区别和定义
131 0
|
6月前
|
C++
C++野指针 空指针 危险指针
C++野指针 空指针 危险指针
|
6月前
|
存储 C语言 C++
什么是函数的指针
什么是函数的指针
24 0
|
存储 算法 编译器
指针(一)------指针概念+指针类型+野指针+指针运算+二级指针
指针(一)------指针概念+指针类型+野指针+指针运算+二级指针
75 0
学C的第十七天【指针初阶: 1. 指针是什么?;2. 指针和指针类型;3. 野指针;4. 指针运算】2
3. 野指针 概念:野指针就是这种指向的位置时不可知的(随机的、不正确的、没有明确限制的)
|
存储
学C的第十七天【指针初阶: 1. 指针是什么?;2. 指针和指针类型;3. 野指针;4. 指针运算】1
1. 指针是什么? (1). 指针是内存中一个最小单元的编号,也就是地址 (2). 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量 总结:指针就是地址,口语中说的指针通常指的是指针变量
|
存储 编译器 Linux
危险的指针---字符指针和字符数组指针所导致的段错误
危险的指针---字符指针和字符数组指针所导致的段错误
124 0
指针及其应用3——指针与函数
指针及其应用3——指针与函数