C语言二维数组中的*(p+1)的确切含义

各位大师们,烦请指教一二吧。
图片说明
如果是在一维数组中,*(p+1)表示p+1这个地址空间或空间中的值,那么在二维数组中,p+1是指向a[1],*(p+1)是a1这个地址中的值啊?可是为什么会是地址呢?

C 语言数组的规则:如果 A 是数组,A 的值就是 A[0] 的地址。

具体到这个程序:a 的值是 a[0] 的地址,a + 1 的值是 a[1] 的地址。
由于 a[0], a[1] 也是数组,a[0] 的值是 a[0][0] 的地址,a[1] 的值是 a[1][0] 的地址。
*(a+1) 等价于 a[1],是 a[1][0] 的地址。

根据 p 的类型,而且赋值后 p 指向 a[0],所以 *(p+1) 和 *(a+1) 的值相同,
是 a[1][0] 的地址,是 (int *) 类型的指针。printf 以指针形式输出这个地址。

看下面程序:

#include <stdio.h>

int main() {
    int a[2][3] = {1, 2, 3, 4, 5, 6};

    int (*p)[3] = a;

    printf("%p\n", p);
    printf("%d, %d\n", sizeof(p), sizeof(*p)); /* 输出指针和被值元素的大小 */
    printf("%p\n", p+1); /* a[1] 的地址 */
    printf("%p\n", *(p+1)); /* a[1][0] 的地址 */
    printf("%d\n", **(p+1)); /* a[1][0] 的值 */

    return 0;
}

二维数组其实是一个小戏法,本质上还是一维数组——二维下标连续构成的数组又连续构成第一维下标。
你可以像遍历一维数组那样遍历它

其实a[2][3]的调用可以看成是两个调用,首先是对a进行[2]操作,然后再对a[2]的返回值进行[3]操作,而a是一个二维数组,对a进行[2]操作之后返回一个地址并没有什么错。
而int (*p)[3],这个p是一个二维数组的指针,你对他进行*操作得出来的必然会是一个指针。
这是我个人的理解,给你参考一下。

对于%p一般以十六进制整数方式输出指针的值,附加前缀0x。

其实就是个地址啊,你编译器里面可以看到值的,单步调试一下看看

很有趣的一个问题,首先确定一点指针p+1指向的新地址并不是p指向的下一个字节,而是以p指针指向的类型大小作为单位步长。这里p指向int型3维数组,类型大小为12字节(sizeof(*p)=12),所以p+1地址从p原地址增加12字节指向a[1]。

然而,上面打印出的结果*(p+1)却并不是a[1][0]对应的值4,而是a[1][0]的地址,实际上与直接打印p+1是相同的。原因在于p+1后的指针指向的类型仍为int[3],解引用不知道如何正确打印这种类型。所以,如果希望像预期一样*(p+1)能打出值4,需要对指针类型进行强制类型转换,改成如下形式:

 printf("%d", *(int*)(p+1));

顺便说一句,你的printf中用的%p以指针形式打印,这个无论怎样输出都是地址,改成%d应该更适合揭示真正的问题。

先看看作为表达式的 a 是什么,它是两维数组 a 的地址。a[0] 的值是 a 的第1个子数组(包含 3 个整数的一维数组)的地址,
a[1] 的值就是 a 的第2个子数组的地址。再注意,*(a+0) 就是 a[0],*(a + 1) 就是 a[1]。

注意 *(p + 1) 就是 *(a + 1),所以它的值就是 a 的第2个子数组的地址,与 a[1] 的值一样。printf 以指针形式输出这个地址。