双指针输出说明

con*_*boy 0 c arrays pointers pointer-arithmetic

你能解释一下输出如何-4吗?我认为++pp;是UB,但不确定。您的解释将真正有助于理解。big-endian 或 little-endian 机器的输出可能有什么不同吗?

#include <stdio.h>

int a[] = { -1, -2, -3, -4 };
int b[] = { 0, 1, 2, 3 };

int main(void)
{
    int *p[] = { a, b };
    int **pp = p;
    printf("a=%p, b=%p, p=%p, pp=%p\n", (void*)a, (void*)b, (void*)p, (void*)pp);
    ++pp;
    printf("p=%p, pp=%p *pp=%p\n", (void*)p, (void*)pp, (void*)*pp);
    ++*pp;
    printf("p=%p, pp=%p *pp=%p\n", (void*)p, (void*)pp, (void*)*pp);
    ++**pp;

    printf("%d\n", (++**pp)[a]);
}
Run Code Online (Sandbox Code Playgroud)

我的输出:

a=0x107121040, b=0x107121050, p=0x7ffee8adfad0, pp=0x7ffee8adfad0
p=0x7ffee8adfad0, pp=0x7ffee8adfad8 *pp=0x107121050
p=0x7ffee8adfad0, pp=0x7ffee8adfad8 *pp=0x107121054
-4
Run Code Online (Sandbox Code Playgroud)

ideone 输出

Mil*_*nek 5

当您使用数组的名称时(在大多数情况下),它会衰减为指向其第一个元素的指针。这意味着int* p = a;int* p = &a[0];完全相同。

因此,要了解在这种情况下会发生什么,只需逐步完成即可。在您第一次printf调用时,事情看起来像这样:

 pp            p           a
+-------+     +------+     +----+----+----+----+
|   +--------->   +--------> -1 | -2 | -3 | -4 |
+-------+     |      |     +----+----+----+----+
              |      |
              +------+     b
              |      |     +----+----+----+----+
              |  +---------> 0  | 1  | 2  | 3  |
              |      |     +----+----+----+----+
              +------+
Run Code Online (Sandbox Code Playgroud)

pp指向 的第一个元素p,它是指向 的第一个元素的指针a

现在,当您增加 时pp,它会更改为指向 的第二个元素p,它是指向 的第一个元素的指针b

 pp            p           a
+-------+     +------+     +----+----+----+----+
|   +   |     |   +--------> -1 | -2 | -3 | -4 |
+---|---+     |      |     +----+----+----+----+
    |         |      |
    |         +------+     b
    |         |      |     +----+----+----+----+
    +--------->  +---------> 0  | 1  | 2  | 3  |
              |      |     +----+----+----+----+
              +------+
Run Code Online (Sandbox Code Playgroud)

然后你增加*pp. 由于*pp是指向 的第一个元素的b指针,因此该指针递增以指向 的第二个元素b

 pp            p           a
+-------+     +------+     +----+----+----+----+
|   +   |     |   +--------> -1 | -2 | -3 | -4 |
+---|---+     |      |     +----+----+----+----+
    |         |      |
    |         +------+     b
    |         |      |     +----+----+----+----+
    +--------->      |     | 0  | 1  | 2  | 3  |
              |   +  |     +----+-^--+----+----+
              +---|--+            |
                  +---------------+
Run Code Online (Sandbox Code Playgroud)

然后你增加**pp. 此时pp是指向 的第二个元素的指针p*pp也是指向 的第二个元素的指针b。这意味着**pp命名 的第二个元素b。您将其从1增加到2

 pp            p           a
+-------+     +------+     +----+----+----+----+
|   +   |     |   +--------> -1 | -2 | -3 | -4 |
+---|---+     |      |     +----+----+----+----+
    |         |      |
    |         +------+     b
    |         |      |     +----+----+----+----+
    +--------->      |     | 0  | 2  | 2  | 3  |
              |   +  |     +----+-^--+----+----+
              +---|--+            |
                  +---------------+
Run Code Online (Sandbox Code Playgroud)

现在,让我们剖析一下(++**pp)[a]++**pp与之前相同,因此 的第二个元素b增加到3

现在,对于任何指针ptr和整数nptr[n]都与 相同*(ptr + n)。由于加法是可交换的,ptr + n因此与 相同n + ptr。这意味着ptr[n]n[ptr].

将这些放在一起,这意味着(++**pp)[a]与 相同3[a],与 相同a[3]a[3]-4,因此您的结果。