c - 将 2D 数组 reshape 为 3D 数组 C

标签 c

您好,我正在尝试将 matlab 代码转换为 C 语言。在执行此操作时,我必须将 2d 数组 reshape 为 3d 数组。我尝试编写一个函数,如下所示。我得到了here的帮助.

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

#define ZALLOC(item, n, type) if ((item = (type *)calloc((n), sizeof(type))) == NULL) \
                                  fatalx("Unable to allocate %d unit(s) for item\n", n)
int i,j,k,x,y;
static void fatalx(const char *str, size_t n)
{
    fprintf(stderr, "%s: %zu\n", str, n);
    exit(1);
}

static int ***alloc_3d(int ar[][12],int rows, int cols,int levels)
{

    int count = 0;
    int ***array_3d;
    ZALLOC(array_3d, levels, int **);
    for (i = 0; i < levels; i++)
    {
        int **data;
        ZALLOC(data, rows, int *);
        array_3d[i] = data;
        for (j = 0; j < rows; j++)
        {
            int *entries;
            ZALLOC(entries, cols, int);
            array_3d[i][j] = entries;
            for (k = 0; k < cols; k++)
            {
                array_3d[i][j][k] = ar[i][j];
            }
        }
    }
    return array_3d;
}

static void print_3d(int ***a3d, int rows, int cols,int levels)
{
    for (i = 0; i < levels; i++)
    {
        printf("%d:\n", i);
        for (j = 0; j < rows; j++)
        {
            printf("   %d:  ", j);
            for (k = 0; k < cols; k++)
                printf(" %3d", a3d[i][j][k]);
            putchar('\n');
        }
    }
}

static void free_3d(int ***a3d, int levels, int rows)
{
    for (i = 0; i < levels; i++)
    {
        for (j = 0; j < rows; j++)
            free(a3d[i][j]);
        free(a3d[i]);
    }
    free(a3d);
}

int main(void)
{
    int ar[2][12]={
         {1,2,3,4,5,6,7,8,9,10,11,12},
         {13,14,15,16,17,18,19,20,21,22,23,24}
         };
    int d1 = 2;
    int d2 = 3;
    int d3 = 4;
    int ***a3d = alloc_3d(ar,d1, d2, d3);

    print_3d(a3d, d1, d2, d3);
    free_3d(a3d, d3, d2);

    return(0);
}

这不仅给了我错误的值,而且还给了垃圾值。其中第一个切片的 matlab 输出为:

a3d(:,:,1) =

 1     2     3
13    14    15

我的完全不一样

0:
   0:     1   1   1
   1:     2   2   2
1:
   0:    13  13  13
   1:    14  14  14
2:
   0:   1991011277 1991011277 1991011277
   1:     4   4   4
3:
   0:     1   1   1
   1:   6630248 6630248 6630248

正如你所看到的,也有垃圾值(value)。所以我的索引也是错误的。知道如何正确地做到这一点吗? 提前致谢。

最佳答案

事实上,您的示例并未执行 reshape ,因为它创建了一个与原始数组类型完全不同的复合对象。

C 多维数组是数组的数组(数组的数组...)。除了其他重要特征之外,此类数组的所有元素在内存中都是连续的。您还可以构造一个指针数组,并将每个指针初始化为指向其自己的数组,等等。虽然这些类型的对象表面上很相似,因为您可以以大致相同的方式将索引运算符应用于两者,重要的是要理解:

  • 指针数组需要额外的空间来容纳指针,超出它们所指向的空间。
  • 虽然指针数组中的指针在内存中是连续的,但它们所指向的数组可能不是连续的。这往往会导致
    • 如果系统的页面大小不能均匀地划分指向的数组的大小,则会浪费空间,并且
    • 由于引用位置较差,访问数组元素的性能较差。
  • 指针数组更困惑且分配速度更慢,因为需要多次单独调用内存分配函数。
  • 指针数组更困惑且释放速度更慢,因为所有指向的数组也必须单独释放。
  • 另一方面,如果(指向的)成员数组的长度不完全相同,则指针数组可容纳“参差不齐”的多维伪数组。

以下是使用标准 C 多维数组(== 数组的数组)编写的程序的外观:

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

#define ALLOC(p, n) do {                                \
    if (!((p) = calloc((n), sizeof(*(p))))) {           \
        fprintf(stderr, "Memory allocation failure\n"); \
        exit(1);                                        \
    }                                                   \
} while (0)

void *reshape_2d_3d(size_t id1, size_t id2, int iar[][id2],
        size_t od1, size_t od2, size_t od3) {
    // oar is a pointer to a multidimensional array; in this case, it will
    // point to the first element of an array of arrays (of arrays).
    int (*oar)[od2][od3];
    size_t size1 = id1 * id2;
    size_t size2 = od1 * od2 * od3;
    size_t min_size = (size1 <= size2) ? size1 : size2;

    ALLOC(oar, od1);

    // A loop nest could be used here, too, but I find this simpler for
    // tracking the correspondence of array elements.  It also better
    // accommodates the case where the reshaped result has different overall
    // size from the original.
    for (size_t i = 0; i < min_size; i++) {
        oar[i / (od2 * od3)][(i / od3) % od2][i % od3] = iar[i / id2][i % id2];
    }

    return oar;
}

void print_3d(size_t levels, size_t rows, size_t cols, int ar[][rows][cols]) {
    for (int i = 0; i < levels; i++) {
        printf("%d:\n", i);
        for (int j = 0; j < rows; j++) {
            printf("   %d:  ", j);
            for (int k = 0; k < cols; k++) {
                printf(" %3d", ar[i][j][k]);
            }
            putchar('\n');
        }
    }
}

int main(void) {
    int ar[2][12] = {
            {1,2,3,4,5,6,7,8,9,10,11,12},
            {13,14,15,16,17,18,19,20,21,22,23,24}
        };
    int d1 = 2, d2 = 3, d3 = 4;
    int (*a3d)[d2][d3] = reshape_2d_3d(2, 12, ar, d1, d2, d3);

    print_3d(d1, d2, d3, a3d);

    // A single, simple free() is all that's needed
    free(a3d);
}

输出:

0:
   0:     1   2   3   4
   1:     5   6   7   8
   2:     9  10  11  12
1:
   0:    13  14  15  16
   1:    17  18  19  20
   2:    21  22  23  24

请注意,它使用可变长度数组,但无需通常关注堆栈分配。因此,它需要一个符合标准的 C99 编译器,或一个实现 VLA 可选(在该版本中)功能的符合标准的 C2011 编译器。

关于c - 将 2D 数组 reshape 为 3D 数组 C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48526453/

相关文章:

c - 赋值时类型不兼容

c - 如何让程序通过BIOS运行?

python - 与 Project Euler : C vs Python vs Erlang vs Haskell 的速度比较

c - 可以将给定的 C 代码转换为汇编 x86 代码吗?

c - 链接器如何确定 .rodata 部分中某些数据的地址?

c - 为什么代码不能正常工作? CS50问题一半

c - 在c中返回指针的函数(int?)

C++ SHFileOperation 64位操作系统

c - 有没有办法使用 CUPS API 来保留打印作业?

c - 将文件作为参数传递并读取数据