C语言的二维和三维动态连续数组分配

在某些特殊的场合需要动态的数组分配,比如图像处理领域,这就需要用到malloc 和free这对好基友了

本测试纯粹为了学习研究,没有意思去比较C和C++的优劣,或者和其他语言的优劣,因为比起C++,我更喜欢C,因为嵌入式的程序还是用C效率高,虽然编程有点虐心,,,,

在图像处理领域,有时需要动态分配一段内存用于存储图像,大家都知道图像在内存中存储形式都是以连续的一维数组的形式存放,故平常使用就分配一维空间就够了;

可是当我需要处理高维数据时,比如做积分图,积分直方图,还沿用一维的数组形式在编程时的寻址就比较虐心了,所以还是有必要动态分配高维的数组的。
分配前提:分配的空间必须时连续的,也就是从高维向低维变换时,必须可以在一段连续的空间之内按照固定的索引方式能够正确的寻址

我的思路是:从第一维开始动态分配指针数组,逐级的向下分配,每次都从起始地址分配 × 的指针数组,直到最后一维直接分配足够覆盖所有维度的长度的存储空间,然后从高维开始,逐级将其首地址链接起来,最后得到的就是连续的动态数组,,,,,
二维太简单,以三维说事儿,假如要分配 row×col channel 的空间,过程就是:
1. 先分配 row 个二维指针,即一个三维指针数组;
2. 再分配 row×col 个一维指针,即一个二维的指针数组;
3. 然后分配 row×col×channel 个数据单元,即一个一维的指针,指向一个一维数组;
4. 最后从高维 channel 开始,逐级向下,将其再固定的位置,由低维的指针指向对应的元素,直到最后的 row 的那一级;
5. 释放的时候,遵循先释放高维,再释放低维的顺序,逐级释放;

更高维的动态数组分配依此类推

语言表达能力有限,不知看懂没有,假如已经看晕,就向下直接看代码吧,一看就懂了,O(∩_∩)O

先来二维的

/**
 * @brief Alloc a 2D int array
 * @param col
 * @param row
 * @return int
 */
int **array2DI(int row, int col)
{
    int **dst;
    int i;
    dst = (int**)malloc(sizeof(int*)*row);
    dst[0] =(int*)malloc(sizeof(int)*row*col);
    for(i=1;i<row;i++)
        dst[i]=dst[i-1]+col;
    return dst;
}
/**
 * @brief Free a 2D int array
 * @param array
 */
void arrayFree2DI(int **array)
{
    if(array!=NULL)
    {
        free(array[0]);
        free(array);
        array=NULL;
    }
    return;
}

再来三维的

/**
 * @brief Alloc a 3D int array
 * @param row
 * @param col
 * @param channel
 * @return int
 */
int ***array3DI(int row, int col, int channel)
{
    int ***dst,**aa,*a;
    int i,j;
    dst = (int***)malloc(sizeof(int**)*row);
    aa = (int**)malloc(sizeof(int*)*row*col);
    a = (int*)malloc(sizeof(int)*row*col*channel);
    for(i=0;i<row*col;i++)
        aa[i]=&a[i*channel];
    for(j=0;j<row;j++)
        dst[j]=&aa[j*col];
    return dst;
}
/**
 * @brief Free a 3D int array
 * @param array
 */
void arrayFree3DI(int ***array)
{
    if(array!=NULL)
    {
        free(array[0][0]);
        free(array[0]);
        free(array);
        array=NULL;
    }
    return;
}

下面是测试,只测试3维的,2维没意思。

为使得结果更直观,我调用了分配unsigned char类型的函数,每个数据占一个字节,这样地址就是连续的,便于观察

int main(int argc, char **argv)
{
    unsigned char ***p=array3DUC(3,4,5);
    for(int i=0;i<3;i++)
        for(int j=0;j<4;j++)
            for(int k=0;k<5;k++)
                p[i][j][k]=i+j+k;

    for(int i=0;i<3;i++)
    {
        for(int j=0;j<4;j++)
        {
            for(int k=0;k<5;k++)
            {
                printf("p(%d,%d,%d)= %d,%p\t",i,j,k,p[i][j][k],&p[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
    printf("start = %p\tend = %p\tlength = %d\n",&p[0][0][0],&p[2][3][4],&p[2][3][4]-&p[0][0][0]+1);
    arrayFree3DUC(p);
    printf("%p\n",p);
    return 1;
}

结果为

动态数组的测试结果

纵向看第一列,可以发现,的确是3行,4列,每一个元素有5个通道,大小没错;
再看地址,从第一个元素到最后一个,都是连续的,也没有问题;
再看长度,3*4*5=60,的确有60个元素;
当释放空间之后,编译器给出错误信息,说明空间的确释放掉了。

好了,就酱紫,欢迎评论,交流,大家共同进步,我也是新手。大神如果发现我有错误,还望及时指出,不胜感激。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值