【问题标题】:Allocating contiguous memory for a 3D array in C在 C 中为 3D 数组分配连续内存
【发布时间】:2016-12-30 16:34:37
【问题描述】:

我需要为 3D 数组分配连续空间。 (编辑:)我想我应该在第一时间明确这一点,但在实际的生产代码中,直到运行时我才会知道数组的尺寸。为了简单起见,我在下面的玩具代码中将它们作为常量提供。我知道坚持使用连续空间的潜在问题,但我必须拥有它。我已经看到如何为 2D 数组执行此操作,但显然我不明白如何将模式扩展到 3D。当我调用函数释放内存时,free_3d_arr,我得到一个错误:

lowest lvl
mid lvl
a.out(2248,0x7fff72d37000) malloc: *** error for object 0x7fab1a403310: pointer being freed was not allocated

如果有人能告诉我解决方法是什么,我将不胜感激。代码在这里:

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

int ***calloc_3d_arr(int sizes[3]){

   int ***a;
   int i,j;

   a = calloc(sizes[0],sizeof(int**)); 
   a[0] = calloc(sizes[0]*sizes[1],sizeof(int*));
   a[0][0] = calloc(sizes[0]*sizes[1]*sizes[2],sizeof(int));

   for (j=0; j<sizes[0]; j++) {
      a[j] = (int**)(a[0][0]+sizes[1]*sizes[2]*j);
      for (i=0; i<sizes[1]; i++) {
         a[j][i] = (int*)(a[j]) + sizes[2]*i;
      }
   }

   return a;

}



void free_3d_arr(int ***arr) {

   printf("lowest lvl\n");
   free(arr[0][0]);
   printf("mid lvl\n");
   free(arr[0]);         // <--- This is a problem line, apparently.
   printf("highest lvl\n");
   free(arr);

}



int main() {

   int ***a;
   int sz[] = {5,4,3};
   int i,j,k;

   a = calloc_3d_arr(sz);

   // do stuff with a

   free_3d_arr(a);

}

【问题讨论】:

  • a[0] = ... 后跟 a[j] = ... 似乎很尴尬...
  • 没有 3D 数组,没有任何东西可以作为一个,也不能在你的代码中指向一个!指针不是数组!如果您需要 3D 阵列,请使用一个!哦,成为 3 星 C 程序员可不是恭维。
  • 也就是说,SO 不是众包调试器 - 你应该自己投资调试它。
  • 正在使用的实现是否支持 VLA?如果是,那么就做int array3D[x][y][z];
  • 不反对你所说的。但是,这种没有更多上下文的“抨击”评论对任何人都没有帮助。因为要么你已经知道它,要么你不理解它。朋克! @Olaf

标签: c arrays calloc contiguous


【解决方案1】:

由于您使用的是 C,我建议您使用真正的多维数组:

int (*a)[sz[1]][sz[2]] = calloc(sz[0], sizeof(*a));

这会为您的 3D 阵列分配连续的存储空间。请注意,自 C99 以来,尺寸可以是动态的。您可以像使用指针数组一样访问此数组:

for(int i = 0; i < sz[0]; i++) {
    for(int j = 0; j < sz[1]; j++) {
        for(int k = 0; k < sz[2]; k++) {
            a[i][j][k] = 42;
        }
    }
}

但是,引擎盖下没有指针数组,索引是通过指针算术和数组指针衰减的魔力完成的。而且由于使用了单个calloc() 来分配事物,因此单个free() 足以摆脱它:

free(a);    //that's it.

【讨论】:

  • 吹毛求疵:所有ints 都应该是size_ts。
  • 轻微补充:C11 使 VLA 成为可选(主要嫌疑人是一家众所周知的无法支持 C99 的大公司和一些销售仅与 C90 兼容的昂贵工具的嵌入式编译器供应商)。也就是说,现代编译器将支持 VLA。
  • @Bob__ 谢谢 :-) 我总是忘记 calloc() 使用这种 interesting 拆分它的大小参数,而 malloc() 没有。但我现在解决了这个问题。
  • @alk 哦,但是它们与sz 的元素进行比较,int 的数组。您不希望我将有符号与无符号进行比较,对吗 ;-) (当然我认为您是对的,sz 应该定义为size_t 的数组,但我为此使用了 OP 的定义.)
【解决方案2】:

你可以这样做:

int ***allocateLinearMemory(int x, int y, int z)
{
    int *p = (int*) malloc(x * y * z * sizeof(int));
    int ***q = (int***) malloc(x * sizeof(int**));
    for (int i = 0; i < x; i++)
    {
        q[i] = (int**) malloc(y * sizeof(int*));
        for (int j = 0; j < y; j++)
        {
            int idx = x*j + x*y*i;
            q[i][j] = &p[idx];
        }
    }
    return q;
} 

void deallocateLinearMemory(int x, int ***q)
{
    free(q[0][0]);
    for(int i = 0; i < x; i++)
    {
        free(q[i]);
    }
    free(q);    
}

我使用它并且工作正常。

【讨论】:

  • 对不起,复制粘贴,知道它的C。
猜你喜欢
  • 1970-01-01
  • 2020-10-23
  • 1970-01-01
  • 1970-01-01
  • 2017-01-12
  • 2021-11-12
  • 2021-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多