一、构建一维数组

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

int main(void)
{
    //开辟有3个元素的一维数组
    int *p = (int *)malloc(3*sizeof(int)); // 开辟3个int的空间
    memset((void *)p, 0, 3*sizeof(int));   //保险起见,我们将空间清零

    int i=0, j=0;

    for(i=0; i<3; i++)
    {
        *(p+i) = i;
    }

    i=0;
    for(i=0; i<3; i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n");

    free(p);

    return 0;
}

一维数组里面的每个元素都是`int`,所以定义的指针`p`的类型为 `int *`

二、构建二维数组

需要开辟 int [3][2]; 的数组

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

int main(void)
{
    //开辟3*2的二维数组
    int (*p)[2] = (int (*)[2])malloc(3*2*sizeof(int));
    memset((void *)p, 0, 3*2*sizeof(int)); //保险起见,我们将空间清零

    int i=0, j=0;
    for(i=0; i<3; i++)
    {
        for(j=0; j<2; j++)
        {
            *(*(p+i)+j) = i + j;
        }
    }

    i=0; j=0;
    for(i=0; i<3; i++)
    {
        for(j=0; j<2; j++)
        {
            printf("%d ", p[i][j]);
        }
        printf("\n");
    }

    free(p);

    return 0;
}

如果将

p = (int (*)[2])malloc(3*2*sizeof(int));

变为

int *p = (int *)malloc(3*2*sizeof(int));

就表示,我们以一个一位数组的方式去访问这个空间,这个一位数组总共6个元素,
所以空间还是那片空间,但是类型不同了,解释方式自然也会发生变化


二维数组的三个元素为一维数组,
p中放的是第0个元素(一维素组)的指针(数组指针),所以p的类型也为int (*)[2]类型


三、构建三维数组

例子3

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

int main(void)
{
    //开辟3*2*2的三维数组
    int (*p)[2][2] = (int (*)[2][2])malloc(3*2*2*sizeof(int));
    memset((void *)p, 0, 3*2*2*sizeof(int)); //保险起见,我们将空间清零

    int i=0, j=0, k=0;
    for(i=0; i<3; i++)
    {
        for(j=0; j<2; j++)
        {
            for(k=0; k<2; k++)
            {
                *(*(*(p+i)+j)+k) = i + j + k;
                //p[i][j][k] = i + j + k;
            }
        }
    }

    i=0; j=0; k=0;
    for(i=0; i<3; i++)
    {
        for(j=0; j<2; j++)
        {
            for(k=0; k<2; k++)
            {
                printf("%d ", p[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }

    free(p);

    return 0;
}

int (*p)[2][2] = (int (*)[2][2])malloc(3*2*2*sizeof(int));

开辟一片3*2*2*sizeof(int)的连续空间,总体上分成3个大的元素,每一个都是一个2个元素的二维数组,
每个二维数组包含两个元素,每个元素是包含两个int元素的一维数组。

三维数组的3个元素为二维数组,类型为int (*)[2][2]
p中放的是第0个元素(二维素组)的指针(二维数组的数组指针),所以p的类型也为int (*)[2][2]类型

*(*(p+i)+j),通过“数组指针 与 第一个元素的指针的转换规则”,最后找到每一个int元素的空间并访问


四、多级指针,创建非传统数组

malloc开辟空间时,通过“多级指针”创建另一种形式的多维数组,
创建一个4*3的新形式的二维数组,不是传统形式的二维数组

#include <stdio.h>

int main(void)
{
    int i = 0, j = 0;
    int **p = NULL; // 开辟二维数组就是2个*,三维就需要3个*,

    p = (int **)malloc( 4 * sizeof(int *) );
    if(NULL != p)
    {
        for(i=0; i<4; i++)
        {
            *(p + i) = malloc( 3 * sizeof(int) );
        }
    }

    for(i=0; i<4; i++)
    {
        for(j=0; j<3; j++)
        {
            *( *( p + i ) + j ) = i+j;
        }
    }

    for(i=0; i<4; i++)
    {
        for(j=0; j<3; j++)
        {
            printf("%d ", *( *( p + i ) + j ) ); //p[i][j]
        }
        printf("\n");
    }

    return 0;
}

通过这种方式新建的数组空间是不连续的,各个都是一维数组,通过指针拼接为多维数组,
显然这种方式与int buf[4][3]不一样,我们将int buf[4][3]方式称为传统方式

释放空间时,只能单个单个的释放:

for(j=0; j<3; j++)
{
    free( *(p+i) );
}
free(p);

五、与传统数组相比*号的作用

1. 在传统的多维数组中 * 的作用

以这个传统的二维数组为例。

int buf[3][2];

*数组指针”的作用为强制转换的作用,将指针类型从“数组指针”强制转换为“第0个元素的指针”

             等价
buf[1][2] <——————> *(*(buf+1)+2)
  • 里面的*:将“数组指针”强制转为第一个元素的指针
  • 外面的*:这一个是解引用

2. 多级指针所构建的多维数组中 * 的作用

*(*(p+i)+j)中,两个*都是解引用的作用

  • (p+i):p+i为p所指向一维数组中的第i个元素指针,元素空间指针的类型为int **
  • *(p+i):对int **类型的指针解引用后,代表的就是第i个元素空间,元素空间存放的是一个int *的指针
  • *(p+i)+j:第i个元素中指针所指向一维数组的第j个元素空间的指针,指针类型为int *
    解引用,找到p所指向一维数组中的第i个元素空间
  • *(*(p+i)+j):解引用,为第j个空间,空间类型为int,找到空间后就可以访问了

所以在“多级指针”构建的多为数组中,*的作用为解引用,不是进行强制转换,但是同样可以等价为[]方式

                 等价
*(*(p+i)+j)  <——————————> p[i][j]