数组从指针索引

时间:2013-02-22 19:02:50

标签: c++ pointers multidimensional-array

考虑以下代码:

static char a[2][2] = {
    { 1, 2 },
    { 3, 4 },
};

int main()
{
    char **p = (char**)a; // needs cast, or compiler complains (which makes sense)

    printf("%p\n", p);

    printf("%p\n", &a[1][0]);
    printf("%d\n",  a[1][0]);
    printf("%p\n", &p[1][0]); // why null?  why doesn't compiler complain about this?
    printf("%d\n",  p[1][0]); // segfault, of course

    return 0;
}

产生此输出:

0x804a018
0x804a01a
3
(nil)
Segmentation fault

我知道数组可以衰减为指针。我不明白为什么编译器(g ++)会让我尝试反过来。如果p是char **,为什么它让我使用p [x] [x]而不是警告?它显然甚至没有接近工作,因为结果指针为空。

顺便说一句,我问的是第三方的代码,显然对他们有效。 (在Windows中编译,而不是使用g ++编译)。所以,我不是在寻找有关如何修复此代码的建议,我已经知道如何做到这一点。我只想了解编译器为什么不抱怨,以及为什么结果是空指针。

感谢。

3 个答案:

答案 0 :(得分:6)

您无法像char那样开始处理char**的二维数组。在内存中,数组看起来像这样:

| 1 | 2 | 3 | 4 |

每个元素都遵循前一个元素。数组名称将隐式转换为指向其第一个元素的指针:

| 1 | 2 | 3 | 4 |
  ^
  |

现在,如果你将这个指针转换为char**,你会说“如果你取消引用这个指针,你会发现char*”,这是一个彻头彻尾的谎言。如果您取消引用指针,则会得到值char的{​​{1}},而不是指针。

然后,当您执行1时,您正在处理p[1][0]处的值(基本上将pointe p[1]移动到p)作为指针并尝试取消引用它。当然,这会引导你直接进入未定义的行为。

编译器没有让你做那个演员,因为这是一个愚蠢的演员。不要这样做。仅仅因为C风格的演员阵容允许你这样做,这并不意味着它是一个好的操作。如果没有其他演员工作,C风格的演员表将回退到sizeof(char*),在这种情况下,你几乎肯定会遇到未定义的行为。

答案 1 :(得分:2)

实际给出答案:a是一个数组。对于像char* p = a;这样的语句,a会自动衰减到指向第一个元素{ 1, 2 }的指针,因为这是一个数组,它也会衰减为它的第一个元素1然而char**p = aa仍然衰减到array of array of char,然后您将整个数组投射到an array of pointers to chars :(它解释为{0x01020304, 0x????????}),这根本没有意义。它是指向数组的指针,而不是指向指针的指针。 那是为什么你需要演员,因为它没有意义。

其次,当您键入p[1]时,它会将该数据(及其后的几个字节)视为char指针数组{0x01020304, 0x00000000},并返回第二个数据元件。 (我们可以看到它在这种特殊情况下都是零,因为这是后来在屏幕上打印的内容),然后[0]取消引用 第二个神秘未知指针恰好是NULL,给你一个段错误。

答案 2 :(得分:0)

当你这样说时:

char a[2][2];
char **p = (char**)a;

这是一个错误。 a不是指向字符的指针数组。 它是一个存储块数组,每个存储块都是一个字符数组。