char a[3][4] 和char **p之间的联系到底是什么

int main(){
    char a1[3][4]={"1","2","3"};
    char (*p1)[4];
    for(p1=a1;p1<a1+3;p1++){
        printf("%s\n",*p1);
    }

    printf("\n");

    char *a2[3]={"1","2","3"};
    char **p2;
    for(p2=a2;p2<a2+3;p2++){
        printf("%s\n",*p2);
    }
    return 0;
}

执行结果都一样,分别拆开每段我也都懂,我就好奇char a[3][4]char **p
之间到底有没有联系,这种联系该怎么通过代码构建?

char a[3][4]可以认为是char **p的特例。
char **p可以代表 char *p[],这里作为元素成员的指针可以不连续。连续是特列。
这种特例就是 char p[][]。