如何在C中初始化3D连续数组

时间:2015-09-30 19:02:58

标签: c arrays

我知道如何以下列方式执行一个不可能的非连续数组:

int main () {
  int ***array = (int***)malloc(3*sizeof(int**));
  int i, j;

  for (i = 0; i < 3; i++) {
    // Assign to array[i], not *array[i] (that would dereference an uninitialized pointer)
    array[i] = (int**)malloc(3*sizeof(int*));
    for (j = 0; j < 3; j++) {
      array[i][j] = (int*)malloc(3*sizeof(int));
    }
  }

  array[1][2][1] = 10;

  return 0;
}

使用上面的代码,数组[0] [j]块可能不连续。为了获得连续性,我觉得我们需要以这种方式使用malloc

int* array = (int*)malloc(3*3*3*sizeof(int));
int** y = (int**)malloc(3*3*sizeof(int**));
int*** x = (int***)malloc(3*sizeof(int***));

  for(i = 0; i < 3; i++)
    {
      vals = vals + i*m*n;
      x[i] = &vals;
      for(j = 0; j < 3; j++)
    {
    x[i][j] = vals + j * n;
    }
    }

然而,我遇到了地址分配问题。我不是程序员,任何人都可以纠正我的错吗?提前谢谢......

5 个答案:

答案 0 :(得分:1)

int*** x = (int***)malloc(3*sizeof(int***));

应该是

int*** x = (int***)malloc(3*sizeof(int**));

现在初始化可以是:

  for(i = 0; i < 3; i++)
  {
    x[i] = y + 3*i;
    for(j = 0; j < 3; j++)
    {
      x[i][j] = array + i*3*3 + j*3;
    }
  }

因此x[0]指向y的第一个元素,x[1]指向第四个元素,等等。 并且x[0][0] = y[0]array的第一个,x[0][1] = y[1]array的第四个等等。

答案 1 :(得分:1)

要分配连续的 3D数组,您只需执行以下操作(假设所有维度在编译时都已知):

#define D0 ...
#define D1 ...
#define D2 ...
...
T (*arr)[D1][D2] = malloc( sizeof *arr * D0 ); // for any type T
...
arr[i][j][k] = some_value();
...

arr被声明为指向D1 x D2数组的指针。然后,我们为D0这样的数组(sizeof *arr == sizeof (T [D1][D2]))分配足够的空间。

使用此方法,阵列的所有内存都是连续分配的。此外,您只需要调用free即可释放整个内容。

如果在运行之前不知道您的维度,那么您使用的是C99编译器或支持可变长度数组的C2011编译器,那么您仍然很幸运:

size_t d0, d1, d2;
...
T (*arr)[d1][d2] = malloc( sizeof *arr * d0 );

主要问题是如何将此作为参数传递给函数。假设在编译时已知D1D2,如果您决定将其作为

传递
foo( arr, D0 );

然后foo的原型需要

void foo( T (*aptr)[D1][D2], size_t n ) 
{
  ...
  aptr[i][j][k] = ...;
}

它仅对 n x D1 x D2大小的数组有用。

如果你去VLA路线,你还需要声明尺寸并为它们传递值:

void foo( size_t d0, size_t d1, size_t d2, T (*aptr)[d1][d2] ) // d1 and d2 *must* be 
                                                               // declared before aptr
{
  ...
  arr[i][j][k] = some_value();
}

void bar( void )
{
  size_t d0, d1, d2;
  ...
  T (*arr)[d1][d2] = malloc( sizeof *arr * d0 );
  ...
  foo( d0, d1, d2, arr );
  ...
}

如果您没有支持VLA的编译器,但仍希望连续分配此内存,那么您必须采用旧式路由 - 将其分配为一维数组并进行计算手动补偿:

T *arr = malloc( sizeof *arr * d0 * d1 * d2 );
...
arr[i * d0 * d1 + j * d1 + k] = some_value(); 

答案 2 :(得分:0)

我正在使用一些非常简洁的方法来分配带有行指针的多维数组。函数multi_mallocmulti_free可用于具有任意维度和任意类型的数组,它们基本上适用于所有平台以及C和C ++

你可以分配,例如一个带有行指针递归的三维数组。例如。一个10x20x30维阵列

float*** data = (float***) multi_malloc(sizeof(float),3, 10,20,20);

访问

等元素
data[2][3][4] = 2.0;

并释放所有内容(数据和行指针)

multi_free(data,3);

标题,我认为应该是C的一部分

#pragma once

#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>

#if (defined(_MSC_VER) && defined(_WIN32))
// Note when used inside a namespace, the static is superfluous
# define STATIC_INLINE_BEGIN static inline //__forceinline
# define STATIC_INLINE_END
#elif (defined(__GNUC__))
# define STATIC_INLINE_BEGIN static inline
# if defined(__CYGWIN__)
#  define STATIC_INLINE_END
# else
#  define STATIC_INLINE_END __attribute__ ((always_inline))
# endif
#endif

STATIC_INLINE_BEGIN void* multi_malloc(size_t s, size_t d, ...) STATIC_INLINE_END;

STATIC_INLINE_BEGIN void multi_free(void *r, size_t d) STATIC_INLINE_END;

/** 
 * Allocate multi-dimensional array and establish row pointers
 * 
 * @param s size of each element
 * @param d number of dimension
 * 
 * @return 
 */
STATIC_INLINE_BEGIN void* multi_malloc(size_t s, size_t d, ...) {

  char* tree;

  va_list ap;             /* varargs list traverser */
  size_t max,             /* size of array to be declared */
    *q;                   /* pointer to dimension list */
  char **r,               /* pointer to beginning of the array of the
                           * pointers for a dimension */
    **s1, *t;             /* base pointer to beginning of first array */
  size_t i, j;            /* loop counters */
  size_t *d1;             /* dimension list */

  va_start(ap,d);
  d1 = (size_t *) malloc(d*sizeof(size_t));

  for(i=0;i<d;i++)
    d1[i] = va_arg(ap,size_t);

  r = &tree;
  q = d1;                 /* first dimension */

  if (d==1) {
    max = *q;
    free(d1);
    return malloc(max*d);
  }

  max = 1;
  for (i = 0; i < d - 1; i++, q++) {      /* for each of the dimensions
                                           * but the last */
    max *= (*q);
    r[0]=(char *)malloc(max * sizeof(char **));
    r = (char **) r[0];     /* step through to beginning of next
                             * dimension array */
  }
  max *= s * (size_t) (*q);        /* grab actual array memory */
  r[0] = (char *)malloc(max * sizeof(char));

  /*
   * r is now set to point to the beginning of each array so that we can
   * use it to scan down each array rather than having to go across and
   * then down
   */
  r = (char **) tree;     /* back to the beginning of list of arrays */
  q = d1;                 /* back to the first dimension */
  max = 1;
  for (i = 0; i < d - 2; i++, q++) {    /* we deal with the last
                                         * array of pointers later on */
    max *= (*q);                        /* number of elements in this dimension */
    for (j=1, s1=r+1, t=r[0]; j<max; j++) { /* scans down array for
                                             * first and subsequent
                                             * elements */

      /*  modify each of the pointers so that it points to
       * the correct position (sub-array) of the next
       * dimension array. s1 is the current position in the
       * current array. t is the current position in the
       * next array. t is incremented before s1 is, but it
       * starts off one behind. *(q+1) is the dimension of
       * the next array. */

      *s1 = (t += sizeof (char **) * *(q + 1));
      s1++;
    }
    r = (char **) r[0];     /* step through to begining of next
                             * dimension array */
  }
  max *= (*q);              /* max is total number of elements in the
                             * last pointer array */

  /* same as previous loop, but different size factor */
  for (j = 1, s1 = r + 1, t = r[0]; j < max; j++)
    *s1++ = (t += s * *(q + 1));

  va_end(ap);
  free(d1);

  return((void *)tree);              /* return base pointer */
}

/** 
 * Free multi-dimensional array and corresponding row pointers
 * 
 * @param r data
 * @param d number of dimensions
 */
STATIC_INLINE_BEGIN void multi_free(void *r, size_t d) {

  void **p;
  void *next=NULL;
  size_t i;

  for (p = (void **)r, i = 0; i < d; p = (void **) next,i++)
    if (p != NULL) {
      next = *p;
      free(p);
      p = NULL;
    }
}

答案 3 :(得分:0)

虽然我认为在堆栈上创建的普通数组最好:

int array[3][3][3];//can avoid a lot of free() calls later on

这是一种动态创建3D阵列的方法:
(我在这里使用calloc而不是malloc,因为它创建了初始化的内存空间)

int *** Create3D(int p, int c, int r) 
{
    int ***arr;
    int    x,y;

    arr = calloc(p, sizeof(arr)); //memory for int
    for(x = 0; x < p; x++)
    {
        arr[x] = calloc(c ,sizeof(arr)); //memory for pointers
        for(y = 0; y < c; y++)
        {
            arr[x][y] = calloc(r, sizeof(int));
        }
    }
    return arr;
}

用法 可以是:

int ***array = Create3D(3,3,3);
for(i=0;i<3;i++)
        for(j=0;j<3;j++)
                for(k=0;k<3;k++)
                    array[i][j][k] = (i+1)*(j+1)*(k+1);

请注意,在此示例中不会返回[c] [m] [re] alloc()的返回值。虽然在C中没有严格禁止,但不建议使用。 (在C ++中不是这种情况, 是必需的)
请记住 ,必须释放所有已分配的内容。注意释放是按照分配的相反顺序完成的:

void free3D(int ***arr, int p, int c)
{
    int i,j;
    for(i=0;i<p;i++)
    {
        for(j=0;j<c;j++)
        {
            if(arr[i][j]) free(arr[i][j]);
        }
        if(arr[i]) free(arr[i]);
    }
    if(arr) free(arr);
}

用法 可以是:

free3D(array,3,3);

答案 4 :(得分:0)

您可以为每个项目是二维数组的项目缓冲区分配内存。所以它实际上是一个三维数组:

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

#define N 3

int main()
{
    int (*array)[N][N] = malloc(N * N * N * sizeof(int));

    /* set 0 to all values */
    memset(array, 0, N * N * N * sizeof(int));

    /* use as 3D array */
    array[0][0][0] = 1;
    array[1][1][1] = 2;
    array[2][2][2] = 3;

    int i;
    /* print array as contiguous buffer */
    for (i = 0; i < N * N * N; ++i)
        printf("i: %d\n", ((int*) array)[i]);

    free(array);

    return 0;
}

因此,在内存中array被定位为常规int array[N][N][N]