c - 在一大块中分配 3D 矩阵

标签 c malloc

我想在一个大块中分配一个 3D 矩阵。应该可以以 [i][j][k] 方式访问此矩阵,而不必每次都计算线性化索引。

我认为它应该像下面这样,但是我在填写 ...

时遇到了问题
double ****matrix = (double ****) malloc(...)
for (int i = 0; i < imax; i++) {
    matrix[i] = &matrix[...]
    for (int j = 0; j < jmax; j++) {
        matrix[i][j] = &matrix[...]
            for (int k = 0; k < kmax; k++) {
                matrix[i][j][k] = &matrix[...]
            }
    }
}

最佳答案

为了使单一分配成为可能并起作用,您需要像这样布置生成的内存:

  • imax单位 double **
  • imax * jmax单位 double *
  • imax * jmax * kmax单位 double

此外,' imax单位 double ** ' 必须先分配;您可以对其他两个部分重新排序,但按列出的顺序处理它们是最明智的。

您还需要能够假设 doubledouble * (和 double ** ,但这并不算多)对齐得很好,您可以简单地连续分配 block 。这在类型为 double 的大多数 64 位系统上都适用。 , 但要注意它可能不适用于 32 位系统或除 double 以外的其他类型。 (基本上,假设在 sizeof(double) != sizeof(double *) 时可能会出现问题)。

有了这些注意事项,这段代码就可以正常工作了(在 Mac OS X 10.10.2 上用 GCC 4.9.1 和 Valgrind 版本 valgrind-3.11.0.SVN 测试过):

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

typedef double Element;

static Element ***alloc_3d_matrix(size_t imax, size_t jmax, size_t kmax)
{
    size_t i_size = imax * sizeof(Element **);
    size_t j_size = imax * jmax * sizeof(Element *);
    size_t k_size = imax * jmax * kmax * sizeof(Element);

    Element ***matrix = malloc(i_size + j_size + k_size);

    if (matrix == 0)
        return 0;

    printf("i = %zu, j = %zu, k = %zu; sizes: i = %zu, j = %zu, k = %zu; "
           "%zu bytes total\n",
           imax, jmax, kmax, i_size, j_size, k_size, i_size + j_size + k_size);
    printf("matrix          = %p .. %p\n", (void *)matrix,
           (void *)((char *)matrix + i_size + j_size + k_size));

    Element **j_base = (void *)((char *)matrix + imax * sizeof(Element **));
    printf("j_base = %p\n", (void *)j_base);
    for (size_t i = 0; i < imax; i++)
    {
        matrix[i] = &j_base[i * jmax];
        printf("matrix[%zu]       = %p (%p)\n",
               i, (void *)matrix[i], (void *)&matrix[i]);
    }

    Element *k_base = (void *)((char *)j_base + imax * jmax * sizeof(Element *));
    printf("k_base = %p\n", (void *)k_base);
    for (size_t i = 0; i < imax; i++)
    {
        for (size_t j = 0; j < jmax; j++)
        {
            matrix[i][j] = &k_base[(i * jmax + j) * kmax];
            printf("matrix[%zu][%zu]    = %p (%p)\n",
                   i, j, (void *)matrix[i][j], (void *)&matrix[i][j]);
        }
    }

    /* Diagnostic only */
    for (size_t i = 0; i < imax; i++)
    {
        for (size_t j = 0; j < jmax; j++)
        {
            for (size_t k = 0; k < kmax; k++)
                printf("matrix[%zu][%zu][%zu] = %p\n",
                       i, j, k, (void *)&matrix[i][j][k]);
        }
    }

    return matrix;
}

int main(void)
{
    size_t i_max = 3;
    size_t j_max = 4;
    size_t k_max = 5;

    Element ***matrix = alloc_3d_matrix(i_max, j_max, k_max);
    if (matrix == 0)
    {
        fprintf(stderr, "Failed to allocate matrix[%zu][%zu][%zu]\n", i_max, j_max, k_max);
        return 1;
    }

    for (size_t i = 0; i < i_max; i++)
    {
        for (size_t j = 0; j < j_max; j++)
        {
            for (size_t k = 0; k < k_max; k++)
                matrix[i][j][k] = (i + 1) * 100 + (j + 1) * 10 + k + 1;
        }
    }

    for (size_t i = 0; i < i_max; i++)
    {
        for (size_t j = 0; j < j_max; j++)
        {
            for (size_t k = k_max; k > 0; k--)
                printf("[%zu][%zu][%zu] = %6.0f\n", i, j, k-1, matrix[i][j][k-1]);
        }
    }

    free(matrix);
    return 0;
}

示例输出(省略了一些无聊的位):

i = 3, j = 4, k = 5; sizes: i = 24, j = 96, k = 480; 600 bytes total
matrix          = 0x100821630 .. 0x100821888
j_base = 0x100821648
matrix[0]       = 0x100821648 (0x100821630)
matrix[1]       = 0x100821668 (0x100821638)
matrix[2]       = 0x100821688 (0x100821640)
k_base = 0x1008216a8
matrix[0][0]    = 0x1008216a8 (0x100821648)
matrix[0][1]    = 0x1008216d0 (0x100821650)
matrix[0][2]    = 0x1008216f8 (0x100821658)
matrix[0][3]    = 0x100821720 (0x100821660)
matrix[1][0]    = 0x100821748 (0x100821668)
matrix[1][1]    = 0x100821770 (0x100821670)
matrix[1][2]    = 0x100821798 (0x100821678)
matrix[1][3]    = 0x1008217c0 (0x100821680)
matrix[2][0]    = 0x1008217e8 (0x100821688)
matrix[2][1]    = 0x100821810 (0x100821690)
matrix[2][2]    = 0x100821838 (0x100821698)
matrix[2][3]    = 0x100821860 (0x1008216a0)
matrix[0][0][0] = 0x1008216a8
matrix[0][0][1] = 0x1008216b0
matrix[0][0][2] = 0x1008216b8
matrix[0][0][3] = 0x1008216c0
matrix[0][0][4] = 0x1008216c8
matrix[0][1][0] = 0x1008216d0
matrix[0][1][1] = 0x1008216d8
matrix[0][1][2] = 0x1008216e0
matrix[0][1][3] = 0x1008216e8
matrix[0][1][4] = 0x1008216f0
matrix[0][2][0] = 0x1008216f8
…
matrix[2][2][4] = 0x100821858
matrix[2][3][0] = 0x100821860
matrix[2][3][1] = 0x100821868
matrix[2][3][2] = 0x100821870
matrix[2][3][3] = 0x100821878
matrix[2][3][4] = 0x100821880
[0][0][4] =    115
[0][0][3] =    114
[0][0][2] =    113
[0][0][1] =    112
[0][0][0] =    111
[0][1][4] =    125
[0][1][3] =    124
[0][1][2] =    123
[0][1][1] =    122
[0][1][0] =    121
[0][2][4] =    135
…
[2][2][0] =    331
[2][3][4] =    345
[2][3][3] =    344
[2][3][2] =    343
[2][3][1] =    342
[2][3][0] =    341

显示的代码中有很多诊断输出。

此代码适用于 C89(以及 C99 和 C11),无需支持可变长度数组或 VLA — 尽管因为我在 for 中声明了变量循环,所编写的代码需要 C99 或更高版本,但可以轻松修复以在 for 之外声明变量循环,然后它可以用 C89 编译。

关于c - 在一大块中分配 3D 矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28818521/

相关文章:

C 中使用强制转换将字符串转换为 int

c - avconv 在 14.04 上从 libx264 管道时提示 "non monotonically increasing dts to muxer in stream"

c - 递归所有 C 文件

c - 在 C 中打印出一个字符串数组

c++ - 使用分配器 Hook 时如何检索被释放的字节?

C 动态内存分配给 void 指针

c - C 中的数组和 malloc

C 具有无限输入的匹配模式

c - 使用指向其结构或结构本身的指针分配内存更好吗?

c - malloc + size_t * 3 的地址是否为任何类型对齐?