修改malloc的二维数组到C中的3d数组的功能

时间:2018-02-18 20:31:36

标签: c arrays 3d malloc

我对C来说很新,这是我写的第一个程序。我的教授给了我们一个为2d数组分配内存的函数,叫做malloc2d。我应该修改它来为3d数组分配内存,但对C来说是新的我不知道如何去做。我已经尝试过查看3D数组的其他malloc函数,但它们看起来与我给出的类似。同样,我们有一个free2d函数,也需要针对3d数组进行修改。以下是要修改的功能:

void** malloc2D(size_t rows, size_t cols, size_t sizeOfType){
    void* block = malloc(sizeOfType * rows * cols);
    void** matrix = malloc(sizeof(void*) * rows);
    for (int row = 0; row < rows; ++row) {
        matrix[row] = block + cols * row * sizeOfType;
    }//for
    return matrix;
}//malloc2D

void free2D(void*** matrix){
    free((*matrix)[0]);
    free((*matrix));
    matrix = NULL;
}//free2D

非常感谢任何帮助或开始。

1 个答案:

答案 0 :(得分:1)

我发现很难相信这是第一次练习;它至少是适度棘手的。

修复二维码

第一步应该是清理malloc2D()函数,以便它不会随便使用GCC扩展 - 索引void * - 因为标准C不允许这样做(因为{{1}在标准C中未定义; GNU C将其定义为1)。此外,sizeof(void)中的错误需要修复;该函数的最后一行应为free2D()(省略*matrix = NULL;)。该代码也应该进行测试,因为访问矩阵的正确方法并不明显。

这是一些修改后的代码(为了与3D版本保持一致而重命名的变量),用于测试修订后的二维码:

*

在运行macOS High Sierra 10.13.3的MacBook Pro上运行时,使用GCC 7.3.0进行编译,得到输出:

/* SO 4885-6272 */

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

/* Should be declared in a header for use in other files */
extern void **malloc2D(size_t rows, size_t cols, size_t sizeOfType);
extern void free2D(void ***matrix);

void **malloc2D(size_t rows, size_t cols, size_t sizeOfType)
{
    void *level2 = malloc(sizeOfType * rows * cols);
    void **level1 = malloc(sizeof(void *) * rows);
    if (level2 == NULL || level1 == NULL)
    {
        free(level2);
        free(level1);
        return NULL;
    }
    for (size_t row = 0; row < rows; ++row)
    {
        level1[row] = (char *)level2 + cols * row * sizeOfType;
    }
    return level1;
}

void free2D(void ***matrix)
{
    free((*matrix)[0]);
    free((*matrix));
    *matrix = NULL;
}

static void test2D(size_t m2_rows, size_t m2_cols)
{
    printf("rows = %zu; cols = %zu\n", m2_rows, m2_cols);
    void **m2 = malloc2D(m2_rows, m2_cols, sizeof(double));
    if (m2 == NULL)
    {
        fprintf(stderr, "Memory allocation failed for 2D array of size %zux%zu doubles\n",
                m2_rows, m2_cols);
        return;
    }

    printf("m2 = 0x%.12" PRIXPTR "; m2[0] = 0x%.12" PRIXPTR "\n",
           (uintptr_t)m2, (uintptr_t)m2[0]);

    for (size_t i = 0; i < m2_rows; i++)
    {
        for (size_t j = 0; j < m2_cols; j++)
            ((double *)m2[i])[j] = (i + 1) * 10 + (j + 1);
    }

    for (size_t i = 0; i < m2_rows; i++)
    {
        for (size_t j = 0; j < m2_cols; j++)
            printf("%4.0f", ((double *)m2[i])[j]);
        putchar('\n');
    }

    free2D(&m2);
    printf("m2 = 0x%.16" PRIXPTR "\n", (uintptr_t)m2);
}

int main(void)
{
    test2D(4, 5);
    test2D(10, 3);
    test2D(3, 10);
    //test2D(300000000, 1000000000);  /* 2132 PiB - should fail to allocate on sane systems! */
    return 0;
}

包含怪物分配后,跟踪结束:

rows = 4; cols = 5
m2 = 0x7F83C04027F0; m2[0] = 0x7F83C0402750
  11  12  13  14  15
  21  22  23  24  25
  31  32  33  34  35
  41  42  43  44  45
m2 = 0x0000000000000000
rows = 10; cols = 3
m2 = 0x7F83C0402750; m2[0] = 0x7F83C04028C0
  11  12  13
  21  22  23
  31  32  33
  41  42  43
  51  52  53
  61  62  63
  71  72  73
  81  82  83
  91  92  93
 101 102 103
m2 = 0x0000000000000000
rows = 3; cols = 10
m2 = 0x7F83C04027A0; m2[0] = 0x7F83C04028C0
  11  12  13  14  15  16  17  18  19  20
  21  22  23  24  25  26  27  28  29  30
  31  32  33  34  35  36  37  38  39  40
m2 = 0x0000000000000000

适应3D代码

我选择将3D阵列的主要尺寸称为“平面”;每个平面包含一个由alloc3d19(8985,0x7fffa5d79340) malloc: *** mach_vm_map(size=2400000000000000000) failed (error code=3) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug Memory allocation failed for 2D array of size 300000000x1000000000 doubles r列组成的二维数组。

对我来说,我画了一张图表来说服自己我的任务是正确的 - 在我搞砸了几次之后。在前两个表中的每个单元格中,第一个数字是包含数组中单元格的索引号(第一个表中为c),第二个数字是下一级别中单元格的索引号({第一个表中的{1}}。 level1表中的数字只是level2 a。

数组的索引
level3

使用该图表 - 或者在其上潦草地绘制箭头的纸和笔版本,double中的平面level1 (planes: 4) ╔═══════╗ ║ 0: 00 ║ ║ 1: 05 ║ ║ 2: 10 ║ ║ 3: 15 ║ ╚═══════╝ level2 (planes: 4; rows: 5) ╔════════╦════════╦════════╦════════╦════════╗ ║ 00: 00 ║ 01: 06 ║ 02: 12 ║ 03: 18 ║ 04: 24 ║ ║ 05: 30 ║ 06: 36 ║ 07: 42 ║ 08: 48 ║ 09: 54 ║ ║ … ║ … ║ … ║ … ║ … ║ ╚════════╩════════╩════════╩════════╩════════╝ level3 (planes: 4; rows: 5; cols: 6) ╔════╦═════╦═════╦═════╦═════╦═════╗ ║ 0 ║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ ║ 6 ║ 7 ║ 8 ║ 9 ║ 10 ║ 11 ║ ║ 12 ║ 13 ║ 14 ║ 15 ║ 16 ║ 17 ║ Plane 0 ║ 18 ║ 19 ║ 20 ║ 21 ║ 22 ║ 23 ║ ║ 24 ║ 25 ║ 26 ║ 27 ║ 28 ║ 29 ║ ╠════╬═════╬═════╬═════╬═════╬═════╣ ║ 30 ║ 31 ║ 32 ║ 33 ║ 34 ║ 35 ║ ║ 36 ║ 37 ║ 38 ║ 39 ║ 40 ║ 41 ║ Plane 1 ║ … ║ … ║ … ║ … ║ … ║ … ║ ╚════╩═════╩═════╩═════╩═════╩═════╝ 的单元格中的值为p;平面level1的单元格中的值p * rows中的行pr; level2中平面p * rows + r) * cols,行p,单元格r的单元格中的值为c。但价值不是整数;他们是指针。因此,必须按适当的大小缩放值,并将其添加到level3(p * rows + r) * cols + clevel1空间的基址。

这导致了这样的代码:

level2

示例输出(内存分配过大):

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

/* Should be declared in a header for use in other files */
extern void ***malloc3D(size_t planes, size_t rows, size_t cols, size_t sizeOfType);
extern void free3D(void ****matrix);

void ***malloc3D(size_t planes, size_t rows, size_t cols, size_t sizeOfType)
{
    void   *level3 = malloc(sizeOfType * planes * rows * cols);
    void  **level2 = malloc(sizeof(void *) * planes * rows);
    void ***level1 = malloc(sizeof(void **) * planes);
    //printf("planes = %zu; rows = %zu; cols = %zu; ", planes, rows, cols);
    //printf("level1 = 0x%.12" PRIXPTR "; level2 = 0x%.12" PRIXPTR "; level3 = 0x%.12" PRIXPTR "\n",
    //        (uintptr_t)level1, (uintptr_t)level2, (uintptr_t)level3);
    fflush(stdout);
    if (level3 == NULL || level2 == NULL || level1 == NULL)
    {
        free(level3);
        free(level2);
        free(level1);
        return NULL;
    }
    for (size_t plane = 0; plane < planes; plane++)
    {
        level1[plane] = (void **)((char *)level2 + plane * rows * sizeof(void **));
        //printf("level1[%zu]   = 0x%.12" PRIXPTR "\n", plane, (uintptr_t)level1[plane]);
        for (size_t row = 0; row < rows; ++row)
        {
            level2[plane * rows + row] = (char *)level3 + (plane * rows + row) * cols * sizeOfType;
            //printf("  level2[%zu] = 0x%.12" PRIXPTR "\n",
            //       plane * rows + row, (uintptr_t)level2[plane * rows + row]);
        }
    }
    return level1;
}

void free3D(void ****matrix)
{
    free((*matrix)[0][0]);
    free((*matrix)[0]);
    free((*matrix));
    *matrix = NULL;
}

static void test3D(size_t m3_plns, size_t m3_rows, size_t m3_cols)
{
    printf("planes = %zu; rows = %zu; cols = %zu\n", m3_plns, m3_rows, m3_cols);
    void ***m3 = malloc3D(m3_plns, m3_rows, m3_cols, sizeof(double));
    if (m3 == NULL)
    {
        fprintf(stderr, "Memory allocation failed for 3D array of size %zux%zux%zu doubles\n",
                m3_plns, m3_rows, m3_cols);
        return;
    }

    printf("m3 = 0x%.12" PRIXPTR "; m3[0] = 0x%.12" PRIXPTR "; m3[0][0] = 0x%.12" PRIXPTR "\n",
           (uintptr_t)m3, (uintptr_t)m3[0], (uintptr_t)m3[0][0]);

    for (size_t i = 0; i < m3_plns; i++)
    {
        for (size_t j = 0; j < m3_rows; j++)
        {
            for (size_t k = 0; k < m3_cols; k++)
                ((double *)m3[i][j])[k] = (i + 1) * 100 + (j + 1) * 10 + (k + 1);
        }
    }

    for (size_t i = 0; i < m3_plns; i++)
    {
        printf("Plane %zu:\n", i + 1);
        for (size_t j = 0; j < m3_rows; j++)
        {
            for (size_t k = 0; k < m3_cols; k++)
                printf("%4.0f", ((double *)m3[i][j])[k]);
            putchar('\n');
        }
        putchar('\n');
    }

    free3D(&m3);
    printf("m3 = 0x%.16" PRIXPTR "\n", (uintptr_t)m3);
}

int main(void)
{
    test3D(4, 5, 6);
    test3D(3, 4, 10);
    test3D(4, 3, 7);
    test3D(4, 9, 7);
    test3D(30000, 100000, 100000000);  /* 2132 PiB - should fail to allocate on sane systems! */
    return 0;
}