多维数组的连续内存

时间:2019-03-06 02:22:07

标签: c malloc

我相信这段代码会强制3维数组的内存分配是连续的。

void ***calloc_3d_array(size_t n3, size_t n2, size_t n1, size_t size){
  void ***array;
  size_t i, j;

  if ((array = (void***)calloc(n3, sizeof(void**))) == NULL) {
    printf("[calloc_3d] failed to allocate memory for %d 1st-pointers\n",
              (int)n3);
    return NULL;
  }

  if ((array[0] = (void**)calloc(n3*n2, sizeof(void*))) == NULL) {
    printf("[calloc_3d] failed to allocate memory for %d 2nd-pointers\n",
              (int)(n3*n2));
    free((void*)array);
    return NULL;
  }

  for (i=1; i<n3; i++) {
    array[i] = (void**)((unsigned char*)array[0]+i*n2*sizeof(void*));
  }

  if ((array[0][0] = (void*)calloc(n3*n2*n1, size)) == NULL) {
    printf("[calloc_3d] failed to alloc. memory (%d X %d X %d of size %d)\n",
              (int)n3, (int)n2, (int)n1, (int)size);
    free((void*)array[0]);
    free((void*)array);
    return NULL;
  }

  for (j=1; j<n2; j++) {
    array[0][j] = (void**)((unsigned char*)array[0][j-1]+n1*size);
  }

  for (i = 1; i < n3; i++) {
    array[i][0] = (void**)((unsigned char*)array[i-1][0]+n2*n1*size);
    for (j = 1; j < n2; j++) {
      array[i][j] = (void**)((unsigned char*)array[i][j-1]+n1*size);
    }
  }

  return array;
}

我试图将其更改为一个连续分配4维数组的函数。我不完全理解3D情况是否完美无缺,因此抽象到第4维有点不稳定。我几乎不确定到底为什么在任何循环中3d代码中都有array [i] =(void **)或array [i] [j] =(void **),所以在4d代码中我拥有所有数组[i] [j] [k] =(void ***)。这是我目前拥有的

void ****calloc_4d_array(size_t n4, size_t n3, size_t n2, size_t n1, size_t size){
  void ****array;
  size_t i, j, k;

  /* Alloc array of 3d pointers */
  if ((array = (void****)calloc(n4, sizeof(void***))) == NULL) {
    printf("[calloc_3d] failed to allocate memory for %d 1st-pointers\n",
              (int)n4);
    return NULL;
  }

  /* In first slot allocate a entire 2d pointer array */
  if ((array[0] = (void***)calloc(n4*n3, sizeof(void**))) == NULL) {
    printf("[calloc_3d] failed to allocate memory for %d 2nd-pointers\n",
              (int)(n4*n3));
    free((void*)array);
    return NULL;
  }

  /* Loop over slots and adjust address to accommodate 2d pointers */
  for (i = 1; i < n4; i++) {
    array[i] = (void***)((unsigned char*)array[0]+i*n3*sizeof(void**));
  }

  /* In the first 2d pointer, allocate the entire space for 1d pointers*/
  if ((array[0][0] = (void**)calloc(n4*n3*n2, sizeof(void*))) == NULL) {
    printf("[calloc_3d] failed to allocate memory for %d 3rd-pointers\n",
              (int)(n4*n3*n2));
    free((void*)array[0]);
    free((void*)array);
    return NULL;
  }

  /* Loop over other 2d slots and adjust address to accommodate type */
  for (j=1; j<n3; j++) {
    array[0][j] = (void**)((unsigned char*)array[0][j-1]+n2*size);
  }
  for (i=1; i<n4; i++) {
    array[i][0] = (void**)((unsigned char*)array[i-1][0]+n3*n2*size);
    for (j=1; j<n3; j++) {
      array[i][j] = (void**)((unsigned char*)array[i][j-1]+n2*size);
    }
  }

  /* Finally allocate for entire array */
  if ((array[0][0][0] = (void*)calloc(n4*n3*n2*n1, size)) == NULL) {
    printf("[calloc_3d] failed to alloc. memory (%d X %d X %d X %d of size %d)\n",
              (int)n4, (int)n3, (int)n2, (int) n1, (int)size);
    free((void*)array[0][0]);
    free((void*)array[0]);
    free((void*)array);
    return NULL;
  }


  for (k=1; k<n2; k++) {
    array[0][0][k] = (void***)((unsigned char*)array[0][0][k-1]+n1*size);
  }
  for (j=1; j<n3; j++) {
    array[0][j][0] = (void***)((unsigned char*)array[0][j-1][0]+n2*n1*size);
    for (k=1; k<n2; k++) {
      array[0][j][k] = (void***)((unsigned char*)array[0][j][k-1]+n1*size);
    }
  }
  for(i=1; i<n4; i++) {
    array[i][0][0] = (void***)((unsigned char*)array[i-1][0][0]+n3*n2*n1*size);
    for (j=1; j<n3; j++) {
      array[i][j][0] = (void***)((unsigned char*)array[i][j-1][0]+n2*n1*size);
      for (k=1; k<n2; k++) {
        array[i][j][k] = (void***)((unsigned char*)array[i][j][k-1]+n1*size);
      }
    }
  }

  return array;
}

编辑:编译器向我发出了有关我的(void ***)问题的警告,并且array [] []是(void **)似乎很有意义,但是我仍然不知道为什么对array [i] =(void ***)而不是array [i] =(void *)很满意。换句话说,为什么用calloc array[0][0][0] = (void*)calloc(n4*n3*n2*n1, size)它(void *),但是使用位移/设置地址(?)array[0][0][k] = (void***)((unsigned char*)array[0][0][k-1]+n1*size);时为什么(void ***)?我想无论哪种对象array [] [] []都是(void *)或(void ***)。

1 个答案:

答案 0 :(得分:0)

这应该分配2个及以上维度数组,并连续使用递归。建议将FORTRAN用于此类高维计算,这不是高效的内存。该示例似乎是valgrind clean。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void *alloc_nd(int *dim, int nd, size_t size)
{
    assert(nd>=2);
    void **p = malloc(sizeof(void*)*dim[0]);
    if(nd==2) {
        p[0] = malloc(size*dim[0]*dim[1]);
        for(int i=1; i<dim[0]; i++)
            p[i] = p[i-1]+size*dim[1];
    } else {
        int xd[nd-1]; 
        for(int i=1; i<nd; i++)
            xd[i-1] = dim[i];
        xd[0] *= dim[0];        //callapse the 1st two dimension
        p[0] = alloc_nd(xd, nd-1, size);
        for(int i=1; i<dim[0]; i++)
            p[i] = p[i-1]+sizeof(void*)*dim[1];
    }
    return p;
}

void free_nd(void *p, int nd)
{
    if(nd==2) {
        free(((void**)p)[0]);
        free(p);
    } else {
        free_nd(((void**)p)[0], nd-1);
        free(p);
    }
}

int main()
{
    int dim[] = {3,4,5,6};
    int ****array;
    array = (int****)alloc_nd(dim, 4, sizeof(int));
    for(int i0=0; i0<dim[0]; i0++)
        for(int i1=0; i1<dim[1]; i1++)
            for(int i2=0; i2<dim[2]; i2++)
                for(int i3=0; i3<dim[3]; i3++)
                    array[i0][i1][i2][i3] = i0+i1+i2+i3;
    int *p = &array[0][0][0][0];  //do you mean continuous in this way? 
    for(int i=0; i<dim[0]*dim[1]*dim[2]*dim[3]; i++)
        printf("p[%5d]=%d\n", i, p[i]);
    free_nd(array, 4);
    return 0;
}