从指针进行数组索引

array indexing from a pointer

本文关键字:数组 索引 指针      更新时间:2023-10-16

请考虑以下代码:

static char a[2][2] = {
    { 1, 2 },
    { 3, 4 },
};
int main()
{
    char **p = (char**)a; // needs cast, or compiler complains (which makes sense)
    printf("%pn", p);
    printf("%pn", &a[1][0]);
    printf("%dn",  a[1][0]);
    printf("%pn", &p[1][0]); // why null?  why doesn't compiler complain about this?
    printf("%dn",  p[1][0]); // segfault, of course
    return 0;
}

产生以下输出:

0x804a018
0x804a01a
3
(nil)
Segmentation fault

我知道数组可以衰减到指针。 我不明白的是为什么编译器(g++(会让我尝试做相反的事情。 如果 p 是一个字符**,为什么它让我在没有警告的情况下使用 p[x][x]? 它显然甚至无法正常工作,因为生成的指针为空。

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

谢谢。

您根本无法像char**一样开始处理 2D char数组。在内存中,数组如下所示:

| 1 | 2 | 3 | 4 |

每个元素都跟在前一个元素之后。数组名称将被隐式转换为指向其第一个元素的指针:

| 1 | 2 | 3 | 4 |
  ^
  |

现在,如果你把这个指针转换成一个char**,你说"如果你取消引用这个指针,你会发现一个char*",这是一个彻头彻尾的谎言。如果取消引用指针,您将获得值为 1char,而不是指针。

然后当你做p[1][0]时,你把p[1]处的值(实质上是将足尖p移动了sizeof(char*)(作为指针,并试图取消引用它。当然,这会直接导致您出现未定义的行为。

编译器不让你做那个转换,因为这是一个愚蠢的转换。不要这样做。仅仅因为 C 型强制转换允许您这样做,这并不意味着这是一个可以操作的操作。如果没有其他演员表工作,C 型演员表将回退到reinterpret_cast,在这种情况下,您几乎肯定会遇到未定义的行为。

实际上给出一个答案: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 的神秘未知指针,给你一个段错误。

当你这样说时:

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

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