双指针 - 得到意外的输出

Double pointer - getting unexpected output

#include <stdio.h> 
#include <stdlib.h> 

int main()
{
    int a[3][3]={{0,1},{2,3},{5,6}},**b,i,j;
    b=(int **)calloc(3,sizeof(int *));
    for(i=0;i<3;i++)
    {
        b[i]=(int *)calloc(3,sizeof(int));
    }
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
        {
            b[i][j]=(i+1)*(j+1);
        }
    }

    printf("%d %d %d %d\n",*(*a+4),**a+4,*(*b+4),**b+4); 
    printf("%d %d %d %d\n",*(a[2]-2),**(a+2),*(b[2]-2),**(b+2)); 

    return 0;
}

我得到的输出:

3 4 2 5
3 5 6 3

根据我的说法,我应该得到:

3 4 4 5
3 5 4 3

原因:

*(*b+4) = *(b[0]+4)b[0]+4指向b[1][1]所以这个值应该是4,也就是矩阵在1,1位置

的值

*(b[2]-2),现在 b[2]-2 指向 b[1][1],所以值又应该是 4

请告诉我为什么得到不同的输出

当你声明一个像a[3][3]这样的二维数组时,整个数组是连续的,所以a[0][2]后面紧跟着a[1][0]。当您在 a 上使用指针运算时,您可以依靠这种跨行的能力,只要您保持在整个 a 数组内即可。

但是当您使用指针数组时,没有理由期望每一行都与前一行连续。每次调用 malloc() 分配的内存与之前的调用无关。此外,malloc() 必须确保内存针对任何数据类型正确对齐;如果您分配的大小不是它的倍数,则它们不可能是连续的。并且很多动态内存分配器在分配之前存储簿记信息(例如分配的大小,以便free()知道要回收多少内存),这样也可以防止分配是连续的。

访问超出分配大小的内存是未定义的行为。由于 b[0] 指向 3 int 的分配,b[0]+4 在此分配之外,并且 *(b[0]+4) 导致未定义的行为。